Rework gc descriptor to include size information in more cases.
[mono.git] / mcs / mcs / cfold.cs
index 9986c418e0fdf923609d4f6b2be772e19d96aab5..7580124ceead35f46cd9af384fdc17b2fe99dcb8 100644 (file)
 //   Miguel de Icaza (miguel@ximian.com)
 //   Marek Safar (marek.safar@seznam.cz)
 //
-// (C) 2002, 2003 Ximian, Inc.
-//
-
+// Copyright 2002, 2003 Ximian, Inc.
+// Copyright 2003-2011, Novell, Inc.
+// 
 using System;
 
 namespace Mono.CSharp {
 
-       public class ConstantFold {
+       public static class ConstantFold
+       {
+               public static TypeSpec[] CreateBinaryPromotionsTypes (BuiltinTypes types)
+               {
+                       return new TypeSpec[] { 
+                               types.Decimal, types.Double, types.Float,
+                               types.ULong, types.Long, types.UInt
+                       };
+               }
 
                //
                // Performs the numeric promotions on the left and right expresions
-               // and desposits the results on `lc' and `rc'.
+               // and deposits the results on `lc' and `rc'.
                //
                // On success, the types of `lc' and `rc' on output will always match,
                // and the pair will be one of:
                //
-               //   (double, double)
-               //   (float, float)
-               //   (ulong, ulong)
-               //   (long, long)
-               //   (uint, uint)
-               //   (int, int)
-               //   (short, short)   (Happens with enumerations with underlying short type)
-               //   (ushort, ushort) (Happens with enumerations with underlying short type)
-               //
-               static void DoConstantNumericPromotions (EmitContext ec, Binary.Operator oper,
-                                                        ref Constant left, ref Constant right,
-                                                        Location loc)
+               // TODO: BinaryFold should be called as an optimization step only,
+               // error checking here is weak
+               //              
+               static bool DoBinaryNumericPromotions (ResolveContext rc, ref Constant left, ref Constant right)
                {
-                       if (left is DoubleConstant || right is DoubleConstant){
-                               //
-                               // If either side is a double, convert the other to a double
-                               //
-                               if (!(left is DoubleConstant))
-                                       left = left.ToDouble (loc);
-
-                               if (!(right is DoubleConstant))
-                                       right = right.ToDouble (loc);
-                               return;
-                       } else if (left is FloatConstant || right is FloatConstant) {
-                               //
-                               // If either side is a float, convert the other to a float
-                               //
-                               if (!(left is FloatConstant))
-                                       left = left.ToFloat (loc);
+                       TypeSpec ltype = left.Type;
+                       TypeSpec rtype = right.Type;
 
-                               if (!(right is FloatConstant))
-                                       right = right.ToFloat (loc);
-;                              return;
-                       } else if (left is ULongConstant || right is ULongConstant){
-                               //
-                               // If either operand is of type ulong, the other operand is
-                               // converted to type ulong.  or an error ocurrs if the other
-                               // operand is of type sbyte, short, int or long
-                               //
-#if WRONG
-                               Constant match, other;
-#endif
-                                       
-                               if (left is ULongConstant){
-#if WRONG
-                                       other = right;
-                                       match = left;
-#endif
-                                       if (!(right is ULongConstant))
-                                               right = right.ToULong (loc);
-                               } else {
-#if WRONG
-                                       other = left;
-                                       match = right;
-#endif
-                                       left = left.ToULong (loc);
-                               }
+                       foreach (TypeSpec t in rc.BuiltinTypes.BinaryPromotionsTypes) {
+                               if (t == ltype)
+                                       return t == rtype || ConvertPromotion (rc, ref right, ref left, t);
 
-#if WRONG
-                               if (other is SByteConstant || other is ShortConstant ||
-                                   other is IntConstant || other is LongConstant){
-                                       Binary.Error_OperatorAmbiguous
-                                               (loc, oper, other.Type, match.Type);
-                                       left = null;
-                                       right = null;
-                               }
-#endif
-                               return;
-                       } else if (left is LongConstant || right is LongConstant){
-                               //
-                               // If either operand is of type long, the other operand is converted
-                               // to type long.
-                               //
-                               if (!(left is LongConstant))
-                                       left = left.ToLong (loc);
-                               else if (!(right is LongConstant))
-                                       right = right.ToLong (loc);
-                               return;
-                       } else if (left is UIntConstant || right is UIntConstant){
-                               //
-                               // If either operand is of type uint, and the other
-                               // operand is of type sbyte, short or int, the operands are
-                               // converted to type long.
-                               //
-                               Constant other;
-                               if (left is UIntConstant)
-                                       other = right;
-                               else
-                                       other = left;
-
-                               // Nothing to do.
-                               if (other is UIntConstant)
-                                       return;
-
-                               IntConstant ic = other as IntConstant;
-                               if (ic != null){
-                                       if (ic.Value >= 0){
-                                               if (left == other)
-                                                       left = new UIntConstant ((uint) ic.Value, ic.Location);
-                                               else
-                                                       right = new UIntConstant ((uint) ic.Value, ic.Location);
-                                               return;
-                                       }
-                               }
-                               
-                               if (other is SByteConstant || other is ShortConstant || ic != null){
-                                       left = left.ToLong (loc);
-                                       right = right.ToLong (loc);
-                               } else {
-                                       left = left.ToUInt (loc);
-                                       right = left.ToUInt (loc);
-                               }
+                               if (t == rtype)
+                                       return t == ltype || ConvertPromotion (rc, ref left, ref right, t);
+                       }
 
-                               return;
-                       } else if (left is DecimalConstant || right is DecimalConstant) {
-                               if (!(left is DecimalConstant))
-                                       left = left.ToDecimal (loc);
-                               else if (!(right is DecimalConstant))
-                                       right = right.ToDecimal (loc);
-                               return;
-                       } else if (left is EnumConstant || right is EnumConstant){
-                               if (left is EnumConstant)
-                                       left = ((EnumConstant) left).Child;
-                               if (right is EnumConstant)
-                                       right = ((EnumConstant) right).Child;
+                       left = left.ConvertImplicitly (rc.BuiltinTypes.Int);
+                       right = right.ConvertImplicitly (rc.BuiltinTypes.Int);
+                       return left != null && right != null;
+               }
 
-                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
-                               return;
+               static bool ConvertPromotion (ResolveContext rc, ref Constant prim, ref Constant second, TypeSpec type)
+               {
+                       Constant c = prim.ConvertImplicitly (type);
+                       if (c != null) {
+                               prim = c;
+                               return true;
+                       }
 
-                       } else {
-                               //
-                               // Force conversions to int32
-                               //
-                               if (!(left is IntConstant))
-                                       left = left.ToInt (loc);
-                               if (!(right is IntConstant))
-                                       right = right.ToInt (loc);
+                       if (type.BuiltinType == BuiltinTypeSpec.Type.UInt) {
+                               type = rc.BuiltinTypes.Long;
+                               prim = prim.ConvertImplicitly (type);
+                               second = second.ConvertImplicitly (type);
+                               return prim != null && second != null;
                        }
-                       return;
+
+                       return false;
                }
 
-               static void Error_CompileTimeOverflow (Location loc)
+               internal static void Error_CompileTimeOverflow (ResolveContext rc, Location loc)
                {
-                       Report.Error (220, loc, "The operation overflows at compile time in checked mode");
+                       rc.Report.Error (220, loc, "The operation overflows at compile time in checked mode");
                }
                
                /// <summary>
@@ -172,270 +78,242 @@ namespace Mono.CSharp {
                ///
                ///   Returns null if the expression can not be folded.
                /// </summary>
-               static public Expression BinaryFold (EmitContext ec, Binary.Operator oper,
+               static public Constant BinaryFold (ResolveContext ec, Binary.Operator oper,
                                                     Constant left, Constant right, Location loc)
                {
+                       Constant result = null;
+
                        if (left is EmptyConstantCast)
                                return BinaryFold (ec, oper, ((EmptyConstantCast)left).child, right, loc);
 
+                       if (left is SideEffectConstant) {
+                               result = BinaryFold (ec, oper, ((SideEffectConstant) left).value, right, loc);
+                               if (result == null)
+                                       return null;
+                               return new SideEffectConstant (result, left, loc);
+                       }
+
                        if (right is EmptyConstantCast)
                                return BinaryFold (ec, oper, left, ((EmptyConstantCast)right).child, loc);
 
-                       Type lt = left.Type;
-                       Type rt = right.Type;
-                       Type result_type = null;
-                       bool bool_res;
-
-                       //
-                       // Enumerator folding
-                       //
-                       if (rt == lt && left is EnumConstant)
-                               result_type = lt;
-
-                       //
-                       // During an enum evaluation, we need to unwrap enumerations
-                       //
-                       if (ec.InEnumContext){
-                               if (left is EnumConstant)
-                                       left = ((EnumConstant) left).Child;
-                               
-                               if (right is EnumConstant)
-                                       right = ((EnumConstant) right).Child;
+                       if (right is SideEffectConstant) {
+                               result = BinaryFold (ec, oper, left, ((SideEffectConstant) right).value, loc);
+                               if (result == null)
+                                       return null;
+                               return new SideEffectConstant (result, right, loc);
                        }
 
-                       if (left is BoolConstant && right is BoolConstant) {
-                               bool lv = ((BoolConstant) left ).Value;
-                               bool rv = ((BoolConstant) right).Value;
+                       TypeSpec lt = left.Type;
+                       TypeSpec rt = right.Type;
+                       bool bool_res;
+
+                       if (lt.BuiltinType == BuiltinTypeSpec.Type.Bool && lt == rt) {
+                               bool lv = (bool) left.GetValue ();
+                               bool rv = (bool) right.GetValue ();                     
                                switch (oper) {
                                case Binary.Operator.BitwiseAnd:
                                case Binary.Operator.LogicalAnd:
-                                       return new BoolConstant (lv && rv, left.Location);
+                                       return new BoolConstant (ec.BuiltinTypes, lv && rv, left.Location);
                                case Binary.Operator.BitwiseOr:
                                case Binary.Operator.LogicalOr:
-                                       return new BoolConstant (lv || rv, left.Location);
+                                       return new BoolConstant (ec.BuiltinTypes, lv || rv, left.Location);
                                case Binary.Operator.ExclusiveOr:
-                                       return new BoolConstant (lv ^ rv, left.Location);
+                                       return new BoolConstant (ec.BuiltinTypes, lv ^ rv, left.Location);
                                case Binary.Operator.Equality:
-                                       return new BoolConstant (lv == rv, left.Location);
+                                       return new BoolConstant (ec.BuiltinTypes, lv == rv, left.Location);
                                case Binary.Operator.Inequality:
-                                       return new BoolConstant (lv != rv, left.Location);
+                                       return new BoolConstant (ec.BuiltinTypes, lv != rv, left.Location);
+                               }
+                               return null;
+                       }
+
+                       //
+                       // During an enum evaluation, none of the rules are valid
+                       // Not sure whether it is bug in csc or in documentation
+                       //
+                       if (ec.HasSet (ResolveContext.Options.EnumScope)){
+                               if (left is EnumConstant)
+                                       left = ((EnumConstant) left).Child;
+                               
+                               if (right is EnumConstant)
+                                       right = ((EnumConstant) right).Child;
+                       } else if (left is EnumConstant && rt == lt) {
+                               switch (oper){
+                                       ///
+                                       /// E operator |(E x, E y);
+                                       /// E operator &(E x, E y);
+                                       /// E operator ^(E x, E y);
+                                       /// 
+                                       case Binary.Operator.BitwiseOr:
+                                       case Binary.Operator.BitwiseAnd:
+                                       case Binary.Operator.ExclusiveOr:
+                                               result = BinaryFold (ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
+                                               if (result != null)
+                                                       result = result.TryReduce (ec, lt, loc);
+                                               return result;
+
+                                       ///
+                                       /// U operator -(E x, E y);
+                                       /// 
+                                       case Binary.Operator.Subtraction:
+                                               result = BinaryFold (ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
+                                               if (result != null)
+                                                       result = result.TryReduce (ec, EnumSpec.GetUnderlyingType (lt), loc);
+                                               return result;
+
+                                       ///
+                                       /// 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);
+                                       /// 
+                                       case Binary.Operator.Equality:                          
+                                       case Binary.Operator.Inequality:
+                                       case Binary.Operator.LessThan:                          
+                                       case Binary.Operator.GreaterThan:
+                                       case Binary.Operator.LessThanOrEqual:                           
+                                       case Binary.Operator.GreaterThanOrEqual:
+                                               return BinaryFold(ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
                                }
                                return null;
                        }
 
-                       Type wrap_as;
-                       Constant result = null;
                        switch (oper){
                        case Binary.Operator.BitwiseOr:
-                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
-                               if (left == null || right == null)
+                               //
+                               // bool? operator &(bool? x, bool? y);
+                               //
+                               if ((lt.BuiltinType == BuiltinTypeSpec.Type.Bool && right is NullLiteral) ||
+                                       (rt.BuiltinType == BuiltinTypeSpec.Type.Bool && left is NullLiteral)) {
+                                       var b = new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
+
+                                       // false | null => null
+                                       // null | false => null
+                                       if ((right is NullLiteral && left.IsDefaultValue) || (left is NullLiteral && right.IsDefaultValue))
+                                               return Nullable.LiftedNull.CreateFromExpression (ec, b);
+
+                                       // true | null => true
+                                       // null | true => true
+                                       return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, true, loc), b);                                     
+                               }
+
+                               if (!DoBinaryNumericPromotions (ec, ref left, ref right))
                                        return null;
 
                                if (left is IntConstant){
-                                       IntConstant v;
                                        int res = ((IntConstant) left).Value | ((IntConstant) right).Value;
-                                       
-                                       v = new IntConstant (res, left.Location);
-                                       if (result_type == null)
-                                               return v;
-                                       else
-                                               return new EnumConstant (v, result_type);
-                               } else if (left is UIntConstant){
-                                       UIntConstant v;
+
+                                       return new IntConstant (ec.BuiltinTypes, res, left.Location);
+                               }
+                               if (left is UIntConstant){
                                        uint res = ((UIntConstant)left).Value | ((UIntConstant)right).Value;
-                                       
-                                       v = new UIntConstant (res, left.Location);
-                                       if (result_type == null)
-                                               return v;
-                                       else
-                                               return new EnumConstant (v, result_type);
-                               } else if (left is LongConstant){
-                                       LongConstant v;
+
+                                       return new UIntConstant (ec.BuiltinTypes, res, left.Location);
+                               }
+                               if (left is LongConstant){
                                        long res = ((LongConstant)left).Value | ((LongConstant)right).Value;
-                                       
-                                       v = new LongConstant (res, left.Location);
-                                       if (result_type == null)
-                                               return v;
-                                       else
-                                               return new EnumConstant (v, result_type);
-                               } else if (left is ULongConstant){
-                                       ULongConstant v;
+
+                                       return new LongConstant (ec.BuiltinTypes, res, left.Location);
+                               }
+                               if (left is ULongConstant){
                                        ulong res = ((ULongConstant)left).Value |
                                                ((ULongConstant)right).Value;
-                                       
-                                       v = new ULongConstant (res, left.Location);
-                                       if (result_type == null)
-                                               return v;
-                                       else
-                                               return new EnumConstant (v, result_type);
-                               } else if (left is UShortConstant){
-                                       UShortConstant v;
-                                       ushort res = (ushort) (((UShortConstant)left).Value |
-                                                              ((UShortConstant)right).Value);
-                                       
-                                       v = new UShortConstant (res, left.Location);
-                                       if (result_type == null)
-                                               return v;
-                                       else
-                                               return new EnumConstant (v, result_type);
-                               } else if (left is ShortConstant){
-                                       ShortConstant v;
-                                       short res = (short) (((ShortConstant)left).Value |
-                                                            ((ShortConstant)right).Value);
-                                       
-                                       v = new ShortConstant (res, left.Location);
-                                       if (result_type == null)
-                                               return v;
-                                       else
-                                               return new EnumConstant (v, result_type);
+
+                                       return new ULongConstant (ec.BuiltinTypes, res, left.Location);
                                }
                                break;
                                
                        case Binary.Operator.BitwiseAnd:
-                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
-                               if (left == null || right == null)
+                               //
+                               // bool? operator &(bool? x, bool? y);
+                               //
+                               if ((lt.BuiltinType == BuiltinTypeSpec.Type.Bool && right is NullLiteral) ||
+                                       (rt.BuiltinType == BuiltinTypeSpec.Type.Bool && left is NullLiteral)) {
+                                       var b = new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
+
+                                       // false & null => false
+                                       // null & false => false
+                                       if ((right is NullLiteral && left.IsDefaultValue) || (left is NullLiteral && right.IsDefaultValue))
+                                               return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, false, loc), b);
+
+                                       // true & null => null
+                                       // null & true => null
+                                       return Nullable.LiftedNull.CreateFromExpression (ec, b);
+                               }
+
+                               if (!DoBinaryNumericPromotions (ec, ref left, ref right))
                                        return null;
                                
+                               ///
+                               /// int operator &(int x, int y);
+                               /// uint operator &(uint x, uint y);
+                               /// long operator &(long x, long y);
+                               /// ulong operator &(ulong x, ulong y);
+                               ///
                                if (left is IntConstant){
-                                       IntConstant v;
                                        int res = ((IntConstant) left).Value & ((IntConstant) right).Value;
-                                       
-                                       v = new IntConstant (res, left.Location);
-                                       if (result_type == null)
-                                               return v;
-                                       else
-                                               return new EnumConstant (v, result_type);
-                               } else if (left is UIntConstant){
-                                       UIntConstant v;
+                                       return new IntConstant (ec.BuiltinTypes, res, left.Location);
+                               }
+                               if (left is UIntConstant){
                                        uint res = ((UIntConstant)left).Value & ((UIntConstant)right).Value;
-                                       
-                                       v = new UIntConstant (res, left.Location);
-                                       if (result_type == null)
-                                               return v;
-                                       else
-                                               return new EnumConstant (v, result_type);
-                               } else if (left is LongConstant){
-                                       LongConstant v;
+                                       return new UIntConstant (ec.BuiltinTypes, res, left.Location);
+                               }
+                               if (left is LongConstant){
                                        long res = ((LongConstant)left).Value & ((LongConstant)right).Value;
-                                       
-                                       v = new LongConstant (res, left.Location);
-                                       if (result_type == null)
-                                               return v;
-                                       else
-                                               return new EnumConstant (v, result_type);
-                               } else if (left is ULongConstant){
-                                       ULongConstant v;
+                                       return new LongConstant (ec.BuiltinTypes, res, left.Location);
+                               }
+                               if (left is ULongConstant){
                                        ulong res = ((ULongConstant)left).Value &
                                                ((ULongConstant)right).Value;
-                                       
-                                       v = new ULongConstant (res, left.Location);
-                                       if (result_type == null)
-                                               return v;
-                                       else
-                                               return new EnumConstant (v, result_type);
-                               } else if (left is UShortConstant){
-                                       UShortConstant v;
-                                       ushort res = (ushort) (((UShortConstant)left).Value &
-                                                              ((UShortConstant)right).Value);
-                                       
-                                       v = new UShortConstant (res, left.Location);
-                                       if (result_type == null)
-                                               return v;
-                                       else
-                                               return new EnumConstant (v, result_type);
-                               } else if (left is ShortConstant){
-                                       ShortConstant v;
-                                       short res = (short) (((ShortConstant)left).Value &
-                                                            ((ShortConstant)right).Value);
-                                       
-                                       v = new ShortConstant (res, left.Location);
-                                       if (result_type == null)
-                                               return v;
-                                       else
-                                               return new EnumConstant (v, result_type);
+
+                                       return new ULongConstant (ec.BuiltinTypes, res, left.Location);
                                }
                                break;
 
                        case Binary.Operator.ExclusiveOr:
-                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
-                               if (left == null || right == null)
+                               if (!DoBinaryNumericPromotions (ec, ref left, ref right))
                                        return null;
                                
                                if (left is IntConstant){
-                                       IntConstant v;
                                        int res = ((IntConstant) left).Value ^ ((IntConstant) right).Value;
-                                       
-                                       v = new IntConstant (res, left.Location);
-                                       if (result_type == null)
-                                               return v;
-                                       else
-                                               return new EnumConstant (v, result_type);
-                               } else if (left is UIntConstant){
-                                       UIntConstant v;
+                                       return new IntConstant (ec.BuiltinTypes, res, left.Location);
+                               }
+                               if (left is UIntConstant){
                                        uint res = ((UIntConstant)left).Value ^ ((UIntConstant)right).Value;
-                                       
-                                       v = new UIntConstant (res, left.Location);
-                                       if (result_type == null)
-                                               return v;
-                                       else
-                                               return new EnumConstant (v, result_type);
-                               } else if (left is LongConstant){
-                                       LongConstant v;
+
+                                       return new UIntConstant (ec.BuiltinTypes, res, left.Location);
+                               }
+                               if (left is LongConstant){
                                        long res = ((LongConstant)left).Value ^ ((LongConstant)right).Value;
-                                       
-                                       v = new LongConstant (res, left.Location);
-                                       if (result_type == null)
-                                               return v;
-                                       else
-                                               return new EnumConstant (v, result_type);
-                               } else if (left is ULongConstant){
-                                       ULongConstant v;
+
+                                       return new LongConstant (ec.BuiltinTypes, res, left.Location);
+                               }
+                               if (left is ULongConstant){
                                        ulong res = ((ULongConstant)left).Value ^
                                                ((ULongConstant)right).Value;
-                                       
-                                       v = new ULongConstant (res, left.Location);
-                                       if (result_type == null)
-                                               return v;
-                                       else
-                                               return new EnumConstant (v, result_type);
-                               } else if (left is UShortConstant){
-                                       UShortConstant v;
-                                       ushort res = (ushort) (((UShortConstant)left).Value ^
-                                                              ((UShortConstant)right).Value);
-                                       
-                                       v = new UShortConstant (res, left.Location);
-                                       if (result_type == null)
-                                               return v;
-                                       else
-                                               return new EnumConstant (v, result_type);
-                               } else if (left is ShortConstant){
-                                       ShortConstant v;
-                                       short res = (short)(((ShortConstant)left).Value ^
-                                                           ((ShortConstant)right).Value);
-                                       
-                                       v = new ShortConstant (res, left.Location);
-                                       if (result_type == null)
-                                               return v;
-                                       else
-                                               return new EnumConstant (v, result_type);
+
+                                       return new ULongConstant (ec.BuiltinTypes, res, left.Location);
                                }
                                break;
 
                        case Binary.Operator.Addition:
-                               bool left_is_string = left is StringConstant;
-                               bool right_is_string = right is StringConstant;
+                               if (lt == InternalType.NullLiteral)
+                                       return right;
+
+                               if (rt == InternalType.NullLiteral)
+                                       return left;
 
                                //
                                // If both sides are strings, then concatenate, if
                                // one is a string, and the other is not, then defer
                                // to runtime concatenation
                                //
-                               wrap_as = null;
-                               if (left_is_string || right_is_string){
-                                       if (left_is_string && right_is_string)
-                                               return new StringConstant (
-                                                       ((StringConstant) left).Value +
-                                                       ((StringConstant) right).Value, left.Location);
+                               if (lt.BuiltinType == BuiltinTypeSpec.Type.String || rt.BuiltinType == BuiltinTypeSpec.Type.String){
+                                       if (lt == rt)
+                                               return new StringConstant (ec.BuiltinTypes, (string)left.GetValue () + (string)right.GetValue (),
+                                                       left.Location);
                                        
                                        return null;
                                }
@@ -444,29 +322,32 @@ namespace Mono.CSharp {
                                // handle "E operator + (E x, U y)"
                                // handle "E operator + (Y y, E x)"
                                //
-                               // note that E operator + (E x, E y) is invalid
-                               //
-                               if (left is EnumConstant){
-                                       if (right is EnumConstant){
-                                               return null;
+                               EnumConstant lc = left as EnumConstant;
+                               EnumConstant rc = right as EnumConstant;
+                               if (lc != null || rc != null){
+                                       if (lc == null) {
+                                               lc = rc;
+                                               lt = lc.Type;
+                                               right = left;
                                        }
 
-                                       right = right.ToType (((EnumConstant) left).Child.Type);
+                                       // U has to be implicitly convetible to E.base
+                                       right = right.ConvertImplicitly (lc.Child.Type);
                                        if (right == null)
                                                return null;
 
-                                       wrap_as = left.Type;
-                               } else if (right is EnumConstant){
-                                       left = left.ToType (((EnumConstant) right).Child.Type);
-                                       if (left == null)
+                                       result = BinaryFold (ec, oper, lc.Child, right, loc);
+                                       if (result == null)
+                                               return null;
+
+                                       result = result.TryReduce (ec, lt, loc);
+                                       if (result == null)
                                                return null;
 
-                                       wrap_as = right.Type;
+                                       return new EnumConstant (result, lt);
                                }
 
-                               result = null;
-                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
-                               if (left == null || right == null)
+                               if (!DoBinaryNumericPromotions (ec, ref left, ref right))
                                        return null;
 
                                try {
@@ -479,9 +360,10 @@ namespace Mono.CSharp {
                                                else
                                                        res = unchecked (((DoubleConstant) left).Value +
                                                                         ((DoubleConstant) right).Value);
-                                               
-                                               result = new DoubleConstant (res, left.Location);
-                                       } else if (left is FloatConstant){
+
+                                               return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
+                                       }
+                                       if (left is FloatConstant){
                                                float res;
                                                
                                                if (ec.ConstantCheckState)
@@ -490,8 +372,8 @@ namespace Mono.CSharp {
                                                else
                                                        res = unchecked (((FloatConstant) left).Value +
                                                                         ((FloatConstant) right).Value);
-                                               
-                                               result = new FloatConstant (res, left.Location);
+
+                                               result = new FloatConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is ULongConstant){
                                                ulong res;
                                                
@@ -502,7 +384,7 @@ namespace Mono.CSharp {
                                                        res = unchecked (((ULongConstant) left).Value +
                                                                         ((ULongConstant) right).Value);
 
-                                               result = new ULongConstant (res, left.Location);
+                                               result = new ULongConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is LongConstant){
                                                long res;
                                                
@@ -512,8 +394,8 @@ namespace Mono.CSharp {
                                                else
                                                        res = unchecked (((LongConstant) left).Value +
                                                                         ((LongConstant) right).Value);
-                                               
-                                               result = new LongConstant (res, left.Location);
+
+                                               result = new LongConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is UIntConstant){
                                                uint res;
                                                
@@ -523,8 +405,8 @@ namespace Mono.CSharp {
                                                else
                                                        res = unchecked (((UIntConstant) left).Value +
                                                                         ((UIntConstant) right).Value);
-                                               
-                                               result = new UIntConstant (res, left.Location);
+
+                                               result = new UIntConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is IntConstant){
                                                int res;
 
@@ -535,7 +417,7 @@ namespace Mono.CSharp {
                                                        res = unchecked (((IntConstant) left).Value +
                                                                         ((IntConstant) right).Value);
 
-                                               result = new IntConstant (res, left.Location);
+                                               result = new IntConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is DecimalConstant) {
                                                decimal res;
 
@@ -546,65 +428,51 @@ namespace Mono.CSharp {
                                                        res = unchecked (((DecimalConstant) left).Value +
                                                                ((DecimalConstant) right).Value);
 
-                                               result = new DecimalConstant (res, left.Location);
-                                       } else {
-                                               throw new Exception ( "Unexepected addition input: " + left);
+                                               result = new DecimalConstant (ec.BuiltinTypes, res, left.Location);
                                        }
                                } catch (OverflowException){
-                                       Error_CompileTimeOverflow (loc);
+                                       Error_CompileTimeOverflow (ec, loc);
                                }
 
-                               if (wrap_as != null) {
-                                       try {
-                                               return result.TryReduce (ec, wrap_as, loc);
-                                       }
-                                       catch (OverflowException) {
-                                               return null;
-                                       }
-                               }
-                               else
-                                       return result;
+                               return result;
 
                        case Binary.Operator.Subtraction:
                                //
                                // handle "E operator - (E x, U y)"
                                // handle "E operator - (Y y, E x)"
-                               // handle "U operator - (E x, E y)"
                                //
-                               wrap_as = null;
-                               if (left is EnumConstant){
-                                       if (right is EnumConstant){
-                                               if (left.Type != right.Type) {
-                                                       Binary.Error_OperatorCannotBeApplied (loc, "-", left.Type, right.Type);
-                                                       return null;
-                                               }
-
-                                               wrap_as = TypeManager.EnumToUnderlying (left.Type);
-                                               right = ((EnumConstant) right).Child.ToType (wrap_as);
-                                               if (right == null)
-                                                       return null;
-
-                                               left = ((EnumConstant) left).Child.ToType (wrap_as);
-                                               if (left == null)
-                                                       return null;
+                               lc = left as EnumConstant;
+                               rc = right as EnumConstant;
+                               if (lc != null || rc != null){
+                                       if (lc == null) {
+                                               lc = rc;
+                                               lt = lc.Type;
+                                               right = left;
                                        }
-                                       else {
-                                               right = right.ToType (((EnumConstant) left).Child.Type);
-                                               if (right == null)
-                                                       return null;
 
-                                               wrap_as = left.Type;
-                                       }
-                               } else if (right is EnumConstant){
-                                       left = left.ToType (((EnumConstant) right).Child.Type);
-                                       if (left == null)
+                                       // U has to be implicitly convetible to E.base
+                                       right = right.ConvertImplicitly (lc.Child.Type);
+                                       if (right == null)
+                                               return null;
+
+                                       result = BinaryFold (ec, oper, lc.Child, right, loc);
+                                       if (result == null)
+                                               return null;
+
+                                       result = result.TryReduce (ec, lt, loc);
+                                       if (result == null)
                                                return null;
 
-                                       wrap_as = right.Type;
+                                       return new EnumConstant (result, lt);
                                }
 
-                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
-                               if (left == null || right == null)
+                               if (left is NullLiteral && right is NullLiteral) {
+                                       var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
+                                       lifted_int.ResolveAsType (ec);
+                                       return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
+                               }
+
+                               if (!DoBinaryNumericPromotions (ec, ref left, ref right))
                                        return null;
 
                                try {
@@ -617,8 +485,8 @@ namespace Mono.CSharp {
                                                else
                                                        res = unchecked (((DoubleConstant) left).Value -
                                                                         ((DoubleConstant) right).Value);
-                                               
-                                               result = new DoubleConstant (res, left.Location);
+
+                                               result = new DoubleConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is FloatConstant){
                                                float res;
                                                
@@ -628,8 +496,8 @@ namespace Mono.CSharp {
                                                else
                                                        res = unchecked (((FloatConstant) left).Value -
                                                                         ((FloatConstant) right).Value);
-                                               
-                                               result = new FloatConstant (res, left.Location);
+
+                                               result = new FloatConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is ULongConstant){
                                                ulong res;
                                                
@@ -639,8 +507,8 @@ namespace Mono.CSharp {
                                                else
                                                        res = unchecked (((ULongConstant) left).Value -
                                                                         ((ULongConstant) right).Value);
-                                               
-                                               result = new ULongConstant (res, left.Location);
+
+                                               result = new ULongConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is LongConstant){
                                                long res;
                                                
@@ -650,8 +518,8 @@ namespace Mono.CSharp {
                                                else
                                                        res = unchecked (((LongConstant) left).Value -
                                                                         ((LongConstant) right).Value);
-                                               
-                                               result = new LongConstant (res, left.Location);
+
+                                               result = new LongConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is UIntConstant){
                                                uint res;
                                                
@@ -661,8 +529,8 @@ namespace Mono.CSharp {
                                                else
                                                        res = unchecked (((UIntConstant) left).Value -
                                                                         ((UIntConstant) right).Value);
-                                               
-                                               result = new UIntConstant (res, left.Location);
+
+                                               result = new UIntConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is IntConstant){
                                                int res;
 
@@ -673,7 +541,7 @@ namespace Mono.CSharp {
                                                        res = unchecked (((IntConstant) left).Value -
                                                                         ((IntConstant) right).Value);
 
-                                               result = new IntConstant (res, left.Location);
+                                               result = new IntConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is DecimalConstant) {
                                                decimal res;
 
@@ -684,28 +552,24 @@ namespace Mono.CSharp {
                                                        res = unchecked (((DecimalConstant) left).Value -
                                                                ((DecimalConstant) right).Value);
 
-                                               return new DecimalConstant (res, left.Location);
+                                               return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
                                        } else {
                                                throw new Exception ( "Unexepected subtraction input: " + left);
                                        }
                                } catch (OverflowException){
-                                       Error_CompileTimeOverflow (loc);
-                               }
-
-                               if (wrap_as != null) {
-                                       try {
-                                               return result.TryReduce (ec, wrap_as, loc);
-                                       }
-                                       catch (OverflowException) {
-                                               return null;
-                                       }
+                                       Error_CompileTimeOverflow (ec, loc);
                                }
 
                                return result;
                                
                        case Binary.Operator.Multiply:
-                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
-                               if (left == null || right == null)
+                               if (left is NullLiteral && right is NullLiteral) {
+                                       var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
+                                       lifted_int.ResolveAsType (ec);
+                                       return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
+                               }
+
+                               if (!DoBinaryNumericPromotions (ec, ref left, ref right))
                                        return null;
 
                                try {
@@ -718,8 +582,8 @@ namespace Mono.CSharp {
                                                else
                                                        res = unchecked (((DoubleConstant) left).Value *
                                                                ((DoubleConstant) right).Value);
-                                               
-                                               return new DoubleConstant (res, left.Location);
+
+                                               return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is FloatConstant){
                                                float res;
                                                
@@ -729,8 +593,8 @@ namespace Mono.CSharp {
                                                else
                                                        res = unchecked (((FloatConstant) left).Value *
                                                                ((FloatConstant) right).Value);
-                                               
-                                               return new FloatConstant (res, left.Location);
+
+                                               return new FloatConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is ULongConstant){
                                                ulong res;
                                                
@@ -740,8 +604,8 @@ namespace Mono.CSharp {
                                                else
                                                        res = unchecked (((ULongConstant) left).Value *
                                                                ((ULongConstant) right).Value);
-                                               
-                                               return new ULongConstant (res, left.Location);
+
+                                               return new ULongConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is LongConstant){
                                                long res;
                                                
@@ -751,8 +615,8 @@ namespace Mono.CSharp {
                                                else
                                                        res = unchecked (((LongConstant) left).Value *
                                                                ((LongConstant) right).Value);
-                                               
-                                               return new LongConstant (res, left.Location);
+
+                                               return new LongConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is UIntConstant){
                                                uint res;
                                                
@@ -762,8 +626,8 @@ namespace Mono.CSharp {
                                                else
                                                        res = unchecked (((UIntConstant) left).Value *
                                                                ((UIntConstant) right).Value);
-                                               
-                                               return new UIntConstant (res, left.Location);
+
+                                               return new UIntConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is IntConstant){
                                                int res;
 
@@ -774,7 +638,7 @@ namespace Mono.CSharp {
                                                        res = unchecked (((IntConstant) left).Value *
                                                                ((IntConstant) right).Value);
 
-                                               return new IntConstant (res, left.Location);
+                                               return new IntConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is DecimalConstant) {
                                                decimal res;
 
@@ -785,18 +649,23 @@ namespace Mono.CSharp {
                                                        res = unchecked (((DecimalConstant) left).Value *
                                                                ((DecimalConstant) right).Value);
 
-                                               return new DecimalConstant (res, left.Location);
+                                               return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
                                        } else {
                                                throw new Exception ( "Unexepected multiply input: " + left);
                                        }
                                } catch (OverflowException){
-                                       Error_CompileTimeOverflow (loc);
+                                       Error_CompileTimeOverflow (ec, loc);
                                }
                                break;
 
                        case Binary.Operator.Division:
-                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
-                               if (left == null || right == null)
+                               if (left is NullLiteral && right is NullLiteral) {
+                                       var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
+                                       lifted_int.ResolveAsType (ec);
+                                       return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
+                               }
+
+                               if (!DoBinaryNumericPromotions (ec, ref left, ref right))
                                        return null;
 
                                try {
@@ -809,8 +678,8 @@ namespace Mono.CSharp {
                                                else
                                                        res = unchecked (((DoubleConstant) left).Value /
                                                                ((DoubleConstant) right).Value);
-                                               
-                                               return new DoubleConstant (res, left.Location);
+
+                                               return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is FloatConstant){
                                                float res;
                                                
@@ -820,8 +689,8 @@ namespace Mono.CSharp {
                                                else
                                                        res = unchecked (((FloatConstant) left).Value /
                                                                ((FloatConstant) right).Value);
-                                               
-                                               return new FloatConstant (res, left.Location);
+
+                                               return new FloatConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is ULongConstant){
                                                ulong res;
                                                
@@ -831,8 +700,8 @@ namespace Mono.CSharp {
                                                else
                                                        res = unchecked (((ULongConstant) left).Value /
                                                                ((ULongConstant) right).Value);
-                                               
-                                               return new ULongConstant (res, left.Location);
+
+                                               return new ULongConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is LongConstant){
                                                long res;
                                                
@@ -842,8 +711,8 @@ namespace Mono.CSharp {
                                                else
                                                        res = unchecked (((LongConstant) left).Value /
                                                                ((LongConstant) right).Value);
-                                               
-                                               return new LongConstant (res, left.Location);
+
+                                               return new LongConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is UIntConstant){
                                                uint res;
                                                
@@ -853,8 +722,8 @@ namespace Mono.CSharp {
                                                else
                                                        res = unchecked (((UIntConstant) left).Value /
                                                                ((UIntConstant) right).Value);
-                                               
-                                               return new UIntConstant (res, left.Location);
+
+                                               return new UIntConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is IntConstant){
                                                int res;
 
@@ -865,7 +734,7 @@ namespace Mono.CSharp {
                                                        res = unchecked (((IntConstant) left).Value /
                                                                ((IntConstant) right).Value);
 
-                                               return new IntConstant (res, left.Location);
+                                               return new IntConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is DecimalConstant) {
                                                decimal res;
 
@@ -876,22 +745,27 @@ namespace Mono.CSharp {
                                                        res = unchecked (((DecimalConstant) left).Value /
                                                                ((DecimalConstant) right).Value);
 
-                                               return new DecimalConstant (res, left.Location);
+                                               return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
                                        } else {
                                                throw new Exception ( "Unexepected division input: " + left);
                                        }
                                } catch (OverflowException){
-                                       Error_CompileTimeOverflow (loc);
+                                       Error_CompileTimeOverflow (ec, loc);
 
                                } catch (DivideByZeroException) {
-                                       Report.Error (020, loc, "Division by constant zero");
+                                       ec.Report.Error (20, loc, "Division by constant zero");
                                }
                                
                                break;
                                
                        case Binary.Operator.Modulus:
-                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
-                               if (left == null || right == null)
+                               if (left is NullLiteral && right is NullLiteral) {
+                                       var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
+                                       lifted_int.ResolveAsType (ec);
+                                       return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
+                               }
+
+                               if (!DoBinaryNumericPromotions (ec, ref left, ref right))
                                        return null;
 
                                try {
@@ -904,8 +778,8 @@ namespace Mono.CSharp {
                                                else
                                                        res = unchecked (((DoubleConstant) left).Value %
                                                                         ((DoubleConstant) right).Value);
-                                               
-                                               return new DoubleConstant (res, left.Location);
+
+                                               return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is FloatConstant){
                                                float res;
                                                
@@ -915,8 +789,8 @@ namespace Mono.CSharp {
                                                else
                                                        res = unchecked (((FloatConstant) left).Value %
                                                                         ((FloatConstant) right).Value);
-                                               
-                                               return new FloatConstant (res, left.Location);
+
+                                               return new FloatConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is ULongConstant){
                                                ulong res;
                                                
@@ -926,8 +800,8 @@ namespace Mono.CSharp {
                                                else
                                                        res = unchecked (((ULongConstant) left).Value %
                                                                         ((ULongConstant) right).Value);
-                                               
-                                               return new ULongConstant (res, left.Location);
+
+                                               return new ULongConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is LongConstant){
                                                long res;
                                                
@@ -937,8 +811,8 @@ namespace Mono.CSharp {
                                                else
                                                        res = unchecked (((LongConstant) left).Value %
                                                                         ((LongConstant) right).Value);
-                                               
-                                               return new LongConstant (res, left.Location);
+
+                                               return new LongConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is UIntConstant){
                                                uint res;
                                                
@@ -948,8 +822,8 @@ namespace Mono.CSharp {
                                                else
                                                        res = unchecked (((UIntConstant) left).Value %
                                                                         ((UIntConstant) right).Value);
-                                               
-                                               return new UIntConstant (res, left.Location);
+
+                                               return new UIntConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is IntConstant){
                                                int res;
 
@@ -960,14 +834,14 @@ namespace Mono.CSharp {
                                                        res = unchecked (((IntConstant) left).Value %
                                                                         ((IntConstant) right).Value);
 
-                                               return new IntConstant (res, left.Location);
+                                               return new IntConstant (ec.BuiltinTypes, res, left.Location);
                                        } else {
                                                throw new Exception ( "Unexepected modulus input: " + left);
                                        }
                                } catch (DivideByZeroException){
-                                       Report.Error (020, loc, "Division by constant zero");
+                                       ec.Report.Error (20, loc, "Division by constant zero");
                                } catch (OverflowException){
-                                       Error_CompileTimeOverflow (loc);
+                                       Error_CompileTimeOverflow (ec, loc);
                                }
                                break;
 
@@ -975,85 +849,93 @@ namespace Mono.CSharp {
                                // There is no overflow checking on left shift
                                //
                        case Binary.Operator.LeftShift:
-                               IntConstant ic = right.ToInt (loc);
+                               if (left is NullLiteral && right is NullLiteral) {
+                                       var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
+                                       lifted_int.ResolveAsType (ec);
+                                       return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
+                               }
+
+                               IntConstant ic = right.ConvertImplicitly (ec.BuiltinTypes.Int) as IntConstant;
                                if (ic == null){
-                                       Binary.Error_OperatorCannotBeApplied (loc, "<<", lt, rt);
+                                       Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
                                        return null;
                                }
-                               int lshift_val = ic.Value;
 
-                               IntConstant lic;
-                               if ((lic = left.ConvertToInt ()) != null)
-                                       return new IntConstant (lic.Value << lshift_val, left.Location);
-
-                               UIntConstant luic;
-                               if ((luic = left.ConvertToUInt ()) != null)
-                                       return new UIntConstant (luic.Value << lshift_val, left.Location);
+                               int lshift_val = ic.Value;
+                               switch (left.Type.BuiltinType) {
+                               case BuiltinTypeSpec.Type.ULong:
+                                       return new ULongConstant (ec.BuiltinTypes, ((ULongConstant) left).Value << lshift_val, left.Location);
+                               case BuiltinTypeSpec.Type.Long:
+                                       return new LongConstant (ec.BuiltinTypes, ((LongConstant) left).Value << lshift_val, left.Location);
+                               case BuiltinTypeSpec.Type.UInt:
+                                       return new UIntConstant (ec.BuiltinTypes, ((UIntConstant) left).Value << lshift_val, left.Location);
+                               }
 
-                               LongConstant llc;
-                               if ((llc = left.ConvertToLong ()) != null)
-                                       return new LongConstant (llc.Value << lshift_val, left.Location);
+                               // null << value => null
+                               if (left is NullLiteral)
+                                       return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
 
-                               ULongConstant lulc;
-                               if ((lulc = left.ConvertToULong ()) != null)
-                                       return new ULongConstant (lulc.Value << lshift_val, left.Location);
+                               left = left.ConvertImplicitly (ec.BuiltinTypes.Int);
+                               if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
+                                       return new IntConstant (ec.BuiltinTypes, ((IntConstant) left).Value << lshift_val, left.Location);
 
-                               Binary.Error_OperatorCannotBeApplied (loc, "<<", lt, rt);
+                               Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
                                break;
 
                                //
                                // There is no overflow checking on right shift
                                //
                        case Binary.Operator.RightShift:
-                               IntConstant sic = right.ToInt (loc);
+                               if (left is NullLiteral && right is NullLiteral) {
+                                       var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
+                                       lifted_int.ResolveAsType (ec);
+                                       return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
+                               }
+
+                               IntConstant sic = right.ConvertImplicitly (ec.BuiltinTypes.Int) as IntConstant;
                                if (sic == null){
-                                       Binary.Error_OperatorCannotBeApplied (loc, ">>", lt, rt);
+                                       Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc); ;
                                        return null;
                                }
                                int rshift_val = sic.Value;
+                               switch (left.Type.BuiltinType) {
+                               case BuiltinTypeSpec.Type.ULong:
+                                       return new ULongConstant (ec.BuiltinTypes, ((ULongConstant) left).Value >> rshift_val, left.Location);
+                               case BuiltinTypeSpec.Type.Long:
+                                       return new LongConstant (ec.BuiltinTypes, ((LongConstant) left).Value >> rshift_val, left.Location);
+                               case BuiltinTypeSpec.Type.UInt:
+                                       return new UIntConstant (ec.BuiltinTypes, ((UIntConstant) left).Value >> rshift_val, left.Location);
+                               }
 
-                               IntConstant ric;
-                               if ((ric = left.ConvertToInt ()) != null)
-                                       return new IntConstant (ric.Value >> rshift_val, left.Location);
-
-                               UIntConstant ruic;
-                               if ((ruic = left.ConvertToUInt ()) != null)
-                                       return new UIntConstant (ruic.Value >> rshift_val, left.Location);
-
-                               LongConstant rlc;
-                               if ((rlc = left.ConvertToLong ()) != null)
-                                       return new LongConstant (rlc.Value >> rshift_val, left.Location);
+                               // null >> value => null
+                               if (left is NullLiteral)
+                                       return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
 
-                               ULongConstant rulc;
-                               if ((rulc = left.ConvertToULong ()) != null)
-                                       return new ULongConstant (rulc.Value >> rshift_val, left.Location);
+                               left = left.ConvertImplicitly (ec.BuiltinTypes.Int);
+                               if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
+                                       return new IntConstant (ec.BuiltinTypes, ((IntConstant) left).Value >> rshift_val, left.Location);
 
-                               Binary.Error_OperatorCannotBeApplied (loc, ">>", lt, rt);
+                               Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
                                break;
 
                        case Binary.Operator.Equality:
-                               if (left is NullConstant){
-                                       if (right is NullConstant)
-                                               return new BoolConstant (true, left.Location);
-                                       else if (right is StringConstant)
-                                               return new BoolConstant (
-                                                       ((StringConstant) right).Value == null, left.Location);
-                               } else if (right is NullConstant){
-                                       if (left is NullConstant)
-                                               return new BoolConstant (true, left.Location);
-                                       else if (left is StringConstant)
-                                               return new BoolConstant (
-                                                       ((StringConstant) left).Value == null, left.Location);
-                               }
-                               if (left is StringConstant && right is StringConstant){
-                                       return new BoolConstant (
-                                               ((StringConstant) left).Value ==
-                                               ((StringConstant) right).Value, left.Location);
-                                       
+                               if (TypeSpec.IsReferenceType (lt) && TypeSpec.IsReferenceType (rt) ||
+                                       (left is Nullable.LiftedNull && right.IsNull) ||
+                                       (right is Nullable.LiftedNull && left.IsNull)) {
+                                       if (left.IsNull || right.IsNull) {
+                                               return ReducedExpression.Create (
+                                                       new BoolConstant (ec.BuiltinTypes, left.IsNull == right.IsNull, left.Location),
+                                                       new Binary (oper, left, right, loc));
+                                       }
+
+                                       if (left is StringConstant && right is StringConstant)
+                                               return new BoolConstant (ec.BuiltinTypes,
+                                                       ((StringConstant) left).Value == ((StringConstant) right).Value, left.Location);
+
+                                       return null;
                                }
 
-                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
-                               if (left == null || right == null)
+                               if (!DoBinaryNumericPromotions (ec, ref left, ref right))
                                        return null;
 
                                bool_res = false;
@@ -1078,30 +960,26 @@ namespace Mono.CSharp {
                                else
                                        return null;
 
-                               return new BoolConstant (bool_res, left.Location);
+                               return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
 
                        case Binary.Operator.Inequality:
-                               if (left is NullConstant){
-                                       if (right is NullConstant)
-                                               return new BoolConstant (false, left.Location);
-                                       else if (right is StringConstant)
-                                               return new BoolConstant (
-                                                       ((StringConstant) right).Value != null, left.Location);
-                               } else if (right is NullConstant){
-                                       if (left is NullConstant)
-                                               return new BoolConstant (false, left.Location);
-                                       else if (left is StringConstant)
-                                               return new BoolConstant (
-                                                       ((StringConstant) left).Value != null, left.Location);
-                               }
-                               if (left is StringConstant && right is StringConstant){
-                                       return new BoolConstant (
-                                               ((StringConstant) left).Value !=
-                                               ((StringConstant) right).Value, left.Location);
-                                       
+                               if (TypeSpec.IsReferenceType (lt) && TypeSpec.IsReferenceType (rt) ||
+                                       (left is Nullable.LiftedNull && right.IsNull) ||
+                                       (right is Nullable.LiftedNull && left.IsNull)) {
+                                       if (left.IsNull || right.IsNull) {
+                                               return ReducedExpression.Create (
+                                                       new BoolConstant (ec.BuiltinTypes, left.IsNull != right.IsNull, left.Location),
+                                                       new Binary (oper, left, right, loc));
+                                       }
+
+                                       if (left is StringConstant && right is StringConstant)
+                                               return new BoolConstant (ec.BuiltinTypes,
+                                                       ((StringConstant) left).Value != ((StringConstant) right).Value, left.Location);
+
+                                       return null;
                                }
-                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
-                               if (left == null || right == null)
+
+                               if (!DoBinaryNumericPromotions (ec, ref left, ref right))
                                        return null;
 
                                bool_res = false;
@@ -1126,11 +1004,22 @@ namespace Mono.CSharp {
                                else
                                        return null;
 
-                               return new BoolConstant (bool_res, left.Location);
+                               return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
 
                        case Binary.Operator.LessThan:
-                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
-                               if (left == null || right == null)
+                               if (right is NullLiteral) {
+                                       if (left is NullLiteral) {
+                                               var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
+                                               lifted_int.ResolveAsType (ec);
+                                               return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
+                                       }
+
+                                       if (left is Nullable.LiftedNull) {
+                                               return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
+                                       }
+                               }
+
+                               if (!DoBinaryNumericPromotions (ec, ref left, ref right))
                                        return null;
 
                                bool_res = false;
@@ -1155,11 +1044,22 @@ namespace Mono.CSharp {
                                else
                                        return null;
 
-                               return new BoolConstant (bool_res, left.Location);
+                               return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
                                
                        case Binary.Operator.GreaterThan:
-                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
-                               if (left == null || right == null)
+                               if (right is NullLiteral) {
+                                       if (left is NullLiteral) {
+                                               var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
+                                               lifted_int.ResolveAsType (ec);
+                                               return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
+                                       }
+
+                                       if (left is Nullable.LiftedNull) {
+                                               return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
+                                       }
+                               }
+
+                               if (!DoBinaryNumericPromotions (ec, ref left, ref right))
                                        return null;
 
                                bool_res = false;
@@ -1184,11 +1084,22 @@ namespace Mono.CSharp {
                                else
                                        return null;
 
-                               return new BoolConstant (bool_res, left.Location);
+                               return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
 
                        case Binary.Operator.GreaterThanOrEqual:
-                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
-                               if (left == null || right == null)
+                               if (right is NullLiteral) {
+                                       if (left is NullLiteral) {
+                                               var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
+                                               lifted_int.ResolveAsType (ec);
+                                               return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
+                                       }
+
+                                       if (left is Nullable.LiftedNull) {
+                                               return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
+                                       }
+                               }
+
+                               if (!DoBinaryNumericPromotions (ec, ref left, ref right))
                                        return null;
 
                                bool_res = false;
@@ -1213,11 +1124,22 @@ namespace Mono.CSharp {
                                else
                                        return null;
 
-                               return new BoolConstant (bool_res, left.Location);
+                               return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
 
                        case Binary.Operator.LessThanOrEqual:
-                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
-                               if (left == null || right == null)
+                               if (right is NullLiteral) {
+                                       if (left is NullLiteral) {
+                                               var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
+                                               lifted_int.ResolveAsType (ec);
+                                               return (Constant) new Nullable.LiftedBinaryOperator (oper, lifted_int, right, loc).Resolve (ec);
+                                       }
+
+                                       if (left is Nullable.LiftedNull) {
+                                               return (Constant) new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
+                                       }
+                               }
+
+                               if (!DoBinaryNumericPromotions (ec, ref left, ref right))
                                        return null;
 
                                bool_res = false;
@@ -1242,7 +1164,7 @@ namespace Mono.CSharp {
                                else
                                        return null;
 
-                               return new BoolConstant (bool_res, left.Location);
+                               return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
                        }
                                        
                        return null;