Merge pull request #820 from brendanzagaeski/master
[mono.git] / mcs / mcs / cfold.cs
index eb4ef94ecb08d45f9672cf65c505da5b28098992..bea0ee06df05bf7a2e542eacd6dd617bccbb801a 100644 (file)
@@ -6,31 +6,20 @@
 //   Marek Safar (marek.safar@seznam.cz)
 //
 // Copyright 2002, 2003 Ximian, Inc.
-// Copyright 2003-2008, Novell, Inc.
+// Copyright 2003-2011, Novell, Inc.
 // 
 using System;
 
 namespace Mono.CSharp {
 
-       public class ConstantFold {
-
-               static TypeSpec[] binary_promotions;
-
-               public static TypeSpec[] BinaryPromotionsTypes {
-                       get {
-                               if (binary_promotions == null) {
-                                        binary_promotions = new TypeSpec[] { 
-                                               TypeManager.decimal_type, TypeManager.double_type, TypeManager.float_type,
-                                               TypeManager.uint64_type, TypeManager.int64_type, TypeManager.uint32_type };
-                               }
-
-                               return binary_promotions;
-                       }
-               }
-
-               public static void Reset ()
+       public static class ConstantFold
+       {
+               public static TypeSpec[] CreateBinaryPromotionsTypes (BuiltinTypes types)
                {
-                       binary_promotions = null;
+                       return new TypeSpec[] { 
+                               types.Decimal, types.Double, types.Float,
+                               types.ULong, types.Long, types.UInt
+                       };
                }
 
                //
@@ -48,7 +37,7 @@ namespace Mono.CSharp {
                        TypeSpec ltype = left.Type;
                        TypeSpec rtype = right.Type;
 
-                       foreach (TypeSpec t in BinaryPromotionsTypes) {
+                       foreach (TypeSpec t in rc.BuiltinTypes.BinaryPromotionsTypes) {
                                if (t == ltype)
                                        return t == rtype || ConvertPromotion (rc, ref right, ref left, t);
 
@@ -56,23 +45,23 @@ namespace Mono.CSharp {
                                        return t == ltype || ConvertPromotion (rc, ref left, ref right, t);
                        }
 
-                       left = left.ConvertImplicitly (rc, TypeManager.int32_type);
-                       right = right.ConvertImplicitly (rc, TypeManager.int32_type);
+                       left = left.ConvertImplicitly (rc.BuiltinTypes.Int);
+                       right = right.ConvertImplicitly (rc.BuiltinTypes.Int);
                        return left != null && right != null;
                }
 
                static bool ConvertPromotion (ResolveContext rc, ref Constant prim, ref Constant second, TypeSpec type)
                {
-                       Constant c = prim.ConvertImplicitly (rc, type);
+                       Constant c = prim.ConvertImplicitly (type);
                        if (c != null) {
                                prim = c;
                                return true;
                        }
 
-                       if (type == TypeManager.uint32_type) {
-                               type = TypeManager.int64_type;
-                               prim = prim.ConvertImplicitly (rc, type);
-                               second = second.ConvertImplicitly (rc, type);
+                       if (type.BuiltinType == BuiltinTypeSpec.Type.UInt) {
+                               type = rc.BuiltinTypes.Long;
+                               prim = prim.ConvertImplicitly (type);
+                               second = second.ConvertImplicitly (type);
                                return prim != null && second != null;
                        }
 
@@ -118,22 +107,22 @@ namespace Mono.CSharp {
                        TypeSpec rt = right.Type;
                        bool bool_res;
 
-                       if (lt == TypeManager.bool_type && lt == rt) {
+                       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;
                        }
@@ -160,7 +149,7 @@ namespace Mono.CSharp {
                                        case Binary.Operator.ExclusiveOr:
                                                result = BinaryFold (ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
                                                if (result != null)
-                                                       result = result.Resolve (ec).TryReduce (ec, lt, loc);
+                                                       result = result.Reduce (ec, lt);
                                                return result;
 
                                        ///
@@ -169,7 +158,7 @@ namespace Mono.CSharp {
                                        case Binary.Operator.Subtraction:
                                                result = BinaryFold (ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
                                                if (result != null)
-                                                       result = result.Resolve (ec).TryReduce (ec, ((EnumConstant)left).Child.Type, loc);
+                                                       result = result.Reduce (ec, EnumSpec.GetUnderlyingType (lt));
                                                return result;
 
                                        ///
@@ -193,33 +182,67 @@ namespace Mono.CSharp {
 
                        switch (oper){
                        case Binary.Operator.BitwiseOr:
+                               //
+                               // 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 Binary (oper, left, right).ResolveOperator (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){
                                        int res = ((IntConstant) left).Value | ((IntConstant) right).Value;
-                                       
-                                       return new IntConstant (res, left.Location);
+
+                                       return new IntConstant (ec.BuiltinTypes, res, left.Location);
                                }
                                if (left is UIntConstant){
                                        uint res = ((UIntConstant)left).Value | ((UIntConstant)right).Value;
-                                       
-                                       return new UIntConstant (res, left.Location);
+
+                                       return new UIntConstant (ec.BuiltinTypes, res, left.Location);
                                }
                                if (left is LongConstant){
                                        long res = ((LongConstant)left).Value | ((LongConstant)right).Value;
-                                       
-                                       return new LongConstant (res, left.Location);
+
+                                       return new LongConstant (ec.BuiltinTypes, res, left.Location);
                                }
                                if (left is ULongConstant){
                                        ulong res = ((ULongConstant)left).Value |
                                                ((ULongConstant)right).Value;
-                                       
-                                       return new ULongConstant (res, left.Location);
+
+                                       return new ULongConstant (ec.BuiltinTypes, res, left.Location);
                                }
                                break;
                                
                        case Binary.Operator.BitwiseAnd:
+                               //
+                               // 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 Binary (oper, left, right).ResolveOperator (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;
                                
@@ -231,21 +254,21 @@ namespace Mono.CSharp {
                                ///
                                if (left is IntConstant){
                                        int res = ((IntConstant) left).Value & ((IntConstant) right).Value;
-                                       return new IntConstant (res, left.Location);
+                                       return new IntConstant (ec.BuiltinTypes, res, left.Location);
                                }
                                if (left is UIntConstant){
                                        uint res = ((UIntConstant)left).Value & ((UIntConstant)right).Value;
-                                       return new UIntConstant (res, left.Location);
+                                       return new UIntConstant (ec.BuiltinTypes, res, left.Location);
                                }
                                if (left is LongConstant){
                                        long res = ((LongConstant)left).Value & ((LongConstant)right).Value;
-                                       return new LongConstant (res, left.Location);
+                                       return new LongConstant (ec.BuiltinTypes, res, left.Location);
                                }
                                if (left is ULongConstant){
                                        ulong res = ((ULongConstant)left).Value &
                                                ((ULongConstant)right).Value;
-                                       
-                                       return new ULongConstant (res, left.Location);
+
+                                       return new ULongConstant (ec.BuiltinTypes, res, left.Location);
                                }
                                break;
 
@@ -255,46 +278,72 @@ namespace Mono.CSharp {
                                
                                if (left is IntConstant){
                                        int res = ((IntConstant) left).Value ^ ((IntConstant) right).Value;
-                                       return new IntConstant (res, left.Location);
+                                       return new IntConstant (ec.BuiltinTypes, res, left.Location);
                                }
                                if (left is UIntConstant){
                                        uint res = ((UIntConstant)left).Value ^ ((UIntConstant)right).Value;
-                                       
-                                       return  new UIntConstant (res, left.Location);
+
+                                       return new UIntConstant (ec.BuiltinTypes, res, left.Location);
                                }
                                if (left is LongConstant){
                                        long res = ((LongConstant)left).Value ^ ((LongConstant)right).Value;
-                                       
-                                       return new LongConstant (res, left.Location);
+
+                                       return new LongConstant (ec.BuiltinTypes, res, left.Location);
                                }
                                if (left is ULongConstant){
                                        ulong res = ((ULongConstant)left).Value ^
                                                ((ULongConstant)right).Value;
-                                       
-                                       return new ULongConstant (res, left.Location);
+
+                                       return new ULongConstant (ec.BuiltinTypes, res, left.Location);
                                }
                                break;
 
                        case Binary.Operator.Addition:
-                               if (lt == InternalType.Null)
-                                       return right;
-
-                               if (rt == InternalType.Null)
-                                       return left;
-
                                //
-                               // If both sides are strings, then concatenate, if
-                               // one is a string, and the other is not, then defer
-                               // to runtime concatenation
+                               // If both sides are strings, then concatenate
                                //
-                               if (lt == TypeManager.string_type || rt == TypeManager.string_type){
+                               // string operator + (string x, string y)
+                               //
+                               if (lt.BuiltinType == BuiltinTypeSpec.Type.String || rt.BuiltinType == BuiltinTypeSpec.Type.String){
                                        if (lt == rt)
-                                               return new StringConstant ((string)left.GetValue () + (string)right.GetValue (),
+                                               return new StringConstant (ec.BuiltinTypes, (string)left.GetValue () + (string)right.GetValue (),
                                                        left.Location);
-                                       
+
+                                       if (lt == InternalType.NullLiteral)
+                                               return new StringConstant (ec.BuiltinTypes, "" + right.GetValue (), left.Location);
+
+                                       if (rt == InternalType.NullLiteral)
+                                               return new StringConstant (ec.BuiltinTypes, left.GetValue () + "", left.Location);
+
                                        return null;
                                }
 
+                               //
+                               // string operator + (string x, object y)
+                               //
+                               if (lt == InternalType.NullLiteral) {
+                                       if (rt.BuiltinType == BuiltinTypeSpec.Type.Object)
+                                               return new StringConstant (ec.BuiltinTypes, "" + right.GetValue (), left.Location);
+
+                                       if (lt == rt) {
+                                               ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
+                                                       "+", lt.GetSignatureForError (), rt.GetSignatureForError ());
+                                               return null;
+                                       }
+
+                                       return right;
+                               }
+
+                               //
+                               // string operator + (object x, string y)
+                               //
+                               if (rt == InternalType.NullLiteral) {
+                                       if (lt.BuiltinType == BuiltinTypeSpec.Type.Object)
+                                               return new StringConstant (ec.BuiltinTypes, right.GetValue () + "", left.Location);
+       
+                                       return left;
+                               }
+
                                //
                                // handle "E operator + (E x, U y)"
                                // handle "E operator + (Y y, E x)"
@@ -309,7 +358,7 @@ namespace Mono.CSharp {
                                        }
 
                                        // U has to be implicitly convetible to E.base
-                                       right = right.ConvertImplicitly (ec, lc.Child.Type);
+                                       right = right.ConvertImplicitly (lc.Child.Type);
                                        if (right == null)
                                                return null;
 
@@ -317,7 +366,7 @@ namespace Mono.CSharp {
                                        if (result == null)
                                                return null;
 
-                                       result = result.Resolve (ec).TryReduce (ec, lt, loc);
+                                       result = result.Reduce (ec, lt);
                                        if (result == null)
                                                return null;
 
@@ -337,20 +386,20 @@ 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);
                                        }
                                        if (left is FloatConstant){
-                                               float res;
-                                               
+                                               double a, b, res;
+                                               a = ((FloatConstant) left).DoubleValue;
+                                               b = ((FloatConstant) right).DoubleValue;
+
                                                if (ec.ConstantCheckState)
-                                                       res = checked (((FloatConstant) left).Value +
-                                                                      ((FloatConstant) right).Value);
+                                                       res = checked (a + b);
                                                else
-                                                       res = unchecked (((FloatConstant) left).Value +
-                                                                        ((FloatConstant) right).Value);
-                                               
-                                               result = new FloatConstant (res, left.Location);
+                                                       res = unchecked (a + b);
+
+                                               result = new FloatConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is ULongConstant){
                                                ulong res;
                                                
@@ -361,7 +410,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;
                                                
@@ -371,8 +420,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;
                                                
@@ -382,8 +431,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;
 
@@ -394,7 +443,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;
 
@@ -405,7 +454,7 @@ namespace Mono.CSharp {
                                                        res = unchecked (((DecimalConstant) left).Value +
                                                                ((DecimalConstant) right).Value);
 
-                                               result = new DecimalConstant (res, left.Location);
+                                               result = new DecimalConstant (ec.BuiltinTypes, res, left.Location);
                                        }
                                } catch (OverflowException){
                                        Error_CompileTimeOverflow (ec, loc);
@@ -428,7 +477,7 @@ namespace Mono.CSharp {
                                        }
 
                                        // U has to be implicitly convetible to E.base
-                                       right = right.ConvertImplicitly (ec, lc.Child.Type);
+                                       right = right.ConvertImplicitly (lc.Child.Type);
                                        if (right == null)
                                                return null;
 
@@ -436,13 +485,19 @@ namespace Mono.CSharp {
                                        if (result == null)
                                                return null;
 
-                                       result = result.Resolve (ec).TryReduce (ec, lt, loc);
+                                       result = result.Reduce (ec, lt);
                                        if (result == null)
                                                return null;
 
                                        return new EnumConstant (result, lt);
                                }
 
+                               if (left is NullLiteral && right is NullLiteral) {
+                                       var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
+                                       lifted_int.ResolveAsType (ec);
+                                       return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
+                               }
+
                                if (!DoBinaryNumericPromotions (ec, ref left, ref right))
                                        return null;
 
@@ -456,19 +511,19 @@ 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;
-                                               
+                                               double a, b, res;
+                                               a = ((FloatConstant) left).DoubleValue;
+                                               b = ((FloatConstant) right).DoubleValue;
+
                                                if (ec.ConstantCheckState)
-                                                       res = checked (((FloatConstant) left).Value -
-                                                                      ((FloatConstant) right).Value);
+                                                       res = checked (a - b);
                                                else
-                                                       res = unchecked (((FloatConstant) left).Value -
-                                                                        ((FloatConstant) right).Value);
-                                               
-                                               result = new FloatConstant (res, left.Location);
+                                                       res = unchecked (a - b);
+
+                                               result = new FloatConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is ULongConstant){
                                                ulong res;
                                                
@@ -478,8 +533,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;
                                                
@@ -489,8 +544,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;
                                                
@@ -500,8 +555,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;
 
@@ -512,7 +567,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;
 
@@ -523,7 +578,7 @@ 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);
                                        }
@@ -534,6 +589,12 @@ namespace Mono.CSharp {
                                return result;
                                
                        case Binary.Operator.Multiply:
+                               if (left is NullLiteral && right is NullLiteral) {
+                                       var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
+                                       lifted_int.ResolveAsType (ec);
+                                       return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
+                               }
+
                                if (!DoBinaryNumericPromotions (ec, ref left, ref right))
                                        return null;
 
@@ -547,19 +608,19 @@ 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;
-                                               
+                                               double a, b, res;
+                                               a = ((FloatConstant) left).DoubleValue;
+                                               b = ((FloatConstant) right).DoubleValue;
+
                                                if (ec.ConstantCheckState)
-                                                       res = checked (((FloatConstant) left).Value *
-                                                               ((FloatConstant) right).Value);
+                                                       res = checked (a * b);
                                                else
-                                                       res = unchecked (((FloatConstant) left).Value *
-                                                               ((FloatConstant) right).Value);
-                                               
-                                               return new FloatConstant (res, left.Location);
+                                                       res = unchecked (a * b);
+
+                                               return new FloatConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is ULongConstant){
                                                ulong res;
                                                
@@ -569,8 +630,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;
                                                
@@ -580,8 +641,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;
                                                
@@ -591,8 +652,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;
 
@@ -603,7 +664,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;
 
@@ -614,7 +675,7 @@ 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);
                                        }
@@ -624,6 +685,12 @@ namespace Mono.CSharp {
                                break;
 
                        case Binary.Operator.Division:
+                               if (left is NullLiteral && right is NullLiteral) {
+                                       var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
+                                       lifted_int.ResolveAsType (ec);
+                                       return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
+                               }
+
                                if (!DoBinaryNumericPromotions (ec, ref left, ref right))
                                        return null;
 
@@ -637,19 +704,19 @@ 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;
-                                               
+                                               double a, b, res;
+                                               a = ((FloatConstant) left).DoubleValue;
+                                               b = ((FloatConstant) right).DoubleValue;
+
                                                if (ec.ConstantCheckState)
-                                                       res = checked (((FloatConstant) left).Value /
-                                                               ((FloatConstant) right).Value);
+                                                       res = checked (a / b);
                                                else
-                                                       res = unchecked (((FloatConstant) left).Value /
-                                                               ((FloatConstant) right).Value);
-                                               
-                                               return new FloatConstant (res, left.Location);
+                                                       res = unchecked (a / b);
+
+                                               return new FloatConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is ULongConstant){
                                                ulong res;
                                                
@@ -659,8 +726,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;
                                                
@@ -670,8 +737,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;
                                                
@@ -681,8 +748,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;
 
@@ -693,7 +760,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;
 
@@ -704,7 +771,7 @@ 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);
                                        }
@@ -718,6 +785,12 @@ namespace Mono.CSharp {
                                break;
                                
                        case Binary.Operator.Modulus:
+                               if (left is NullLiteral && right is NullLiteral) {
+                                       var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
+                                       lifted_int.ResolveAsType (ec);
+                                       return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
+                               }
+
                                if (!DoBinaryNumericPromotions (ec, ref left, ref right))
                                        return null;
 
@@ -731,19 +804,19 @@ 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;
+                                               double a, b, res;
+                                               a = ((FloatConstant) left).DoubleValue;
+                                               b = ((FloatConstant) right).DoubleValue;
                                                
                                                if (ec.ConstantCheckState)
-                                                       res = checked (((FloatConstant) left).Value %
-                                                                      ((FloatConstant) right).Value);
+                                                       res = checked (a % b);
                                                else
-                                                       res = unchecked (((FloatConstant) left).Value %
-                                                                        ((FloatConstant) right).Value);
-                                               
-                                               return new FloatConstant (res, left.Location);
+                                                       res = unchecked (a % b);
+
+                                               return new FloatConstant (ec.BuiltinTypes, res, left.Location);
                                        } else if (left is ULongConstant){
                                                ulong res;
                                                
@@ -753,8 +826,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;
                                                
@@ -764,8 +837,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;
                                                
@@ -775,8 +848,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;
 
@@ -787,7 +860,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 {
                                                throw new Exception ( "Unexepected modulus input: " + left);
                                        }
@@ -802,61 +875,83 @@ namespace Mono.CSharp {
                                // There is no overflow checking on left shift
                                //
                        case Binary.Operator.LeftShift:
-                               IntConstant ic = right.ConvertImplicitly (ec, TypeManager.int32_type) as IntConstant;
+                               if (left is NullLiteral && right is NullLiteral) {
+                                       var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
+                                       lifted_int.ResolveAsType (ec);
+                                       return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
+                               }
+
+                               IntConstant ic = right.ConvertImplicitly (ec.BuiltinTypes.Int) as IntConstant;
                                if (ic == null){
-                                       Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
                                        return null;
                                }
 
                                int lshift_val = ic.Value;
-                               if (left.Type == TypeManager.uint64_type)
-                                       return new ULongConstant (((ULongConstant)left).Value << lshift_val, left.Location);
-                               if (left.Type == TypeManager.int64_type)
-                                       return new LongConstant (((LongConstant)left).Value << lshift_val, left.Location);
-                               if (left.Type == TypeManager.uint32_type)
-                                       return new UIntConstant (((UIntConstant)left).Value << lshift_val, left.Location);
-
-                               left = left.ConvertImplicitly (ec, TypeManager.int32_type);
-                               if (left.Type == TypeManager.int32_type)
-                                       return new IntConstant (((IntConstant)left).Value << lshift_val, left.Location);
-
-                               Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
-                               break;
+                               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);
+                               }
+
+                               // null << value => null
+                               if (left is NullLiteral)
+                                       return (Constant) new Binary (oper, left, right).ResolveOperator (ec);
+
+                               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);
+
+                               return null;
 
                                //
                                // There is no overflow checking on right shift
                                //
                        case Binary.Operator.RightShift:
-                               IntConstant sic = right.ConvertImplicitly (ec, TypeManager.int32_type) as IntConstant;
+                               if (left is NullLiteral && right is NullLiteral) {
+                                       var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
+                                       lifted_int.ResolveAsType (ec);
+                                       return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
+                               }
+
+                               IntConstant sic = right.ConvertImplicitly (ec.BuiltinTypes.Int) as IntConstant;
                                if (sic == null){
-                                       Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc); ;
                                        return null;
                                }
                                int rshift_val = sic.Value;
-                               if (left.Type == TypeManager.uint64_type)
-                                       return new ULongConstant (((ULongConstant)left).Value >> rshift_val, left.Location);
-                               if (left.Type == TypeManager.int64_type)
-                                       return new LongConstant (((LongConstant)left).Value >> rshift_val, left.Location);
-                               if (left.Type == TypeManager.uint32_type)
-                                       return new UIntConstant (((UIntConstant)left).Value >> rshift_val, left.Location);
-
-                               left = left.ConvertImplicitly (ec, TypeManager.int32_type);
-                               if (left.Type == TypeManager.int32_type)
-                                       return new IntConstant (((IntConstant)left).Value >> rshift_val, left.Location);
-
-                               Binary.Error_OperatorCannotBeApplied (ec, left, right, oper, loc);
-                               break;
+                               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);
+                               }
+
+                               // null >> value => null
+                               if (left is NullLiteral)
+                                       return (Constant) new Binary (oper, left, right).ResolveOperator (ec);
+
+                               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);
+
+                               return null;
 
                        case Binary.Operator.Equality:
-                               if (TypeManager.IsReferenceType (lt) && TypeManager.IsReferenceType (lt)) {
+                               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 (left.IsNull == right.IsNull, left.Location).Resolve (ec),
-                                                       new Binary (oper, left, right, loc));
+                                                       new BoolConstant (ec.BuiltinTypes, left.IsNull == right.IsNull, left.Location),
+                                                       new Binary (oper, left, right));
                                        }
 
                                        if (left is StringConstant && right is StringConstant)
-                                               return new BoolConstant (
+                                               return new BoolConstant (ec.BuiltinTypes,
                                                        ((StringConstant) left).Value == ((StringConstant) right).Value, left.Location);
 
                                        return null;
@@ -870,8 +965,8 @@ namespace Mono.CSharp {
                                        bool_res = ((DoubleConstant) left).Value ==
                                                ((DoubleConstant) right).Value;
                                else if (left is FloatConstant)
-                                       bool_res = ((FloatConstant) left).Value ==
-                                               ((FloatConstant) right).Value;
+                                       bool_res = ((FloatConstant) left).DoubleValue ==
+                                               ((FloatConstant) right).DoubleValue;
                                else if (left is ULongConstant)
                                        bool_res = ((ULongConstant) left).Value ==
                                                ((ULongConstant) right).Value;
@@ -887,18 +982,20 @@ 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 (TypeManager.IsReferenceType (lt) && TypeManager.IsReferenceType (lt)) {
+                               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 (left.IsNull != right.IsNull, left.Location).Resolve (ec),
-                                                       new Binary (oper, left, right, loc));
+                                                       new BoolConstant (ec.BuiltinTypes, left.IsNull != right.IsNull, left.Location),
+                                                       new Binary (oper, left, right));
                                        }
 
                                        if (left is StringConstant && right is StringConstant)
-                                               return new BoolConstant (
+                                               return new BoolConstant (ec.BuiltinTypes,
                                                        ((StringConstant) left).Value != ((StringConstant) right).Value, left.Location);
 
                                        return null;
@@ -912,8 +1009,8 @@ namespace Mono.CSharp {
                                        bool_res = ((DoubleConstant) left).Value !=
                                                ((DoubleConstant) right).Value;
                                else if (left is FloatConstant)
-                                       bool_res = ((FloatConstant) left).Value !=
-                                               ((FloatConstant) right).Value;
+                                       bool_res = ((FloatConstant) left).DoubleValue !=
+                                               ((FloatConstant) right).DoubleValue;
                                else if (left is ULongConstant)
                                        bool_res = ((ULongConstant) left).Value !=
                                                ((ULongConstant) right).Value;
@@ -929,9 +1026,17 @@ 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:
+                               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 Binary (oper, lifted_int, right).ResolveOperator (ec);
+                                       }
+                               }
+
                                if (!DoBinaryNumericPromotions (ec, ref left, ref right))
                                        return null;
 
@@ -940,8 +1045,8 @@ namespace Mono.CSharp {
                                        bool_res = ((DoubleConstant) left).Value <
                                                ((DoubleConstant) right).Value;
                                else if (left is FloatConstant)
-                                       bool_res = ((FloatConstant) left).Value <
-                                               ((FloatConstant) right).Value;
+                                       bool_res = ((FloatConstant) left).DoubleValue <
+                                               ((FloatConstant) right).DoubleValue;
                                else if (left is ULongConstant)
                                        bool_res = ((ULongConstant) left).Value <
                                                ((ULongConstant) right).Value;
@@ -957,9 +1062,17 @@ 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:
+                               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 Binary (oper, lifted_int, right).ResolveOperator (ec);
+                                       }
+                               }
+
                                if (!DoBinaryNumericPromotions (ec, ref left, ref right))
                                        return null;
 
@@ -968,8 +1081,8 @@ namespace Mono.CSharp {
                                        bool_res = ((DoubleConstant) left).Value >
                                                ((DoubleConstant) right).Value;
                                else if (left is FloatConstant)
-                                       bool_res = ((FloatConstant) left).Value >
-                                               ((FloatConstant) right).Value;
+                                       bool_res = ((FloatConstant) left).DoubleValue >
+                                               ((FloatConstant) right).DoubleValue;
                                else if (left is ULongConstant)
                                        bool_res = ((ULongConstant) left).Value >
                                                ((ULongConstant) right).Value;
@@ -985,9 +1098,17 @@ 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:
+                               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 Binary (oper, lifted_int, right).ResolveOperator (ec);
+                                       }
+                               }
+
                                if (!DoBinaryNumericPromotions (ec, ref left, ref right))
                                        return null;
 
@@ -996,8 +1117,8 @@ namespace Mono.CSharp {
                                        bool_res = ((DoubleConstant) left).Value >=
                                                ((DoubleConstant) right).Value;
                                else if (left is FloatConstant)
-                                       bool_res = ((FloatConstant) left).Value >=
-                                               ((FloatConstant) right).Value;
+                                       bool_res = ((FloatConstant) left).DoubleValue >=
+                                               ((FloatConstant) right).DoubleValue;
                                else if (left is ULongConstant)
                                        bool_res = ((ULongConstant) left).Value >=
                                                ((ULongConstant) right).Value;
@@ -1013,9 +1134,17 @@ 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:
+                               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 Binary (oper, lifted_int, right).ResolveOperator (ec);
+                                       }
+                               }
+
                                if (!DoBinaryNumericPromotions (ec, ref left, ref right))
                                        return null;
 
@@ -1024,8 +1153,8 @@ namespace Mono.CSharp {
                                        bool_res = ((DoubleConstant) left).Value <=
                                                ((DoubleConstant) right).Value;
                                else if (left is FloatConstant)
-                                       bool_res = ((FloatConstant) left).Value <=
-                                               ((FloatConstant) right).Value;
+                                       bool_res = ((FloatConstant) left).DoubleValue <=
+                                               ((FloatConstant) right).DoubleValue;
                                else if (left is ULongConstant)
                                        bool_res = ((ULongConstant) left).Value <=
                                                ((ULongConstant) right).Value;
@@ -1041,9 +1170,9 @@ namespace Mono.CSharp {
                                else
                                        return null;
 
-                               return new BoolConstant (bool_res, left.Location);
+                               return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
                        }
-                                       
+
                        return null;
                }
        }