Better messages than a throw
[mono.git] / mcs / mcs / cfold.cs
old mode 100755 (executable)
new mode 100644 (file)
index 3caac94..9465eaa
@@ -26,6 +26,8 @@ namespace Mono.CSharp {
                //   (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,
@@ -57,16 +59,22 @@ namespace Mono.CSharp {
                                // 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);
                                }
 
@@ -96,26 +104,42 @@ namespace Mono.CSharp {
                                // operand is of type sbyte, short or int, the operands are
                                // converted to type long.
                                //
-                               Constant match, other;
-                               if (left is UIntConstant){
+                               Constant other;
+                               if (left is UIntConstant)
                                        other = right;
-                                       match = left;
-                               } else {
+                               else
                                        other = left;
-                                       match = right;
-                               }
 
                                // Nothing to do.
                                if (other is UIntConstant)
                                        return;
 
-                               if (other is SByteConstant || other is ShortConstant ||
-                                   other is IntConstant){
+                               IntConstant ic = other as IntConstant;
+                               if (ic != null){
+                                       if (ic.Value >= 0){
+                                               if (left == other)
+                                                       left = new UIntConstant ((uint) ic.Value);
+                                               else
+                                                       right = new UIntConstant ((uint) ic.Value);
+                                               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);
                                }
 
                                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 either operand is an enum constant, the other one must
@@ -147,6 +171,8 @@ namespace Mono.CSharp {
                                        left = ((EnumConstant) left).Child;
                                if (right is EnumConstant)
                                        right = ((EnumConstant) right).Child;
+
+                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
                                return;
 
                        } else {
@@ -178,7 +204,7 @@ namespace Mono.CSharp {
                        Type rt = right.Type;
                        Type result_type = null;
                        bool bool_res;
-                       
+
                        //
                        // Enumerator folding
                        //
@@ -203,7 +229,7 @@ namespace Mono.CSharp {
                                DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
                                if (left == null || right == null)
                                        return null;
-                               
+
                                if (left is IntConstant){
                                        IntConstant v;
                                        int res = ((IntConstant) left).Value | ((IntConstant) right).Value;
@@ -241,6 +267,26 @@ namespace Mono.CSharp {
                                                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);
+                                       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);
+                                       if (result_type == null)
+                                               return v;
+                                       else
+                                               return new EnumConstant (v, result_type);
                                }
                                break;
                                
@@ -286,6 +332,26 @@ namespace Mono.CSharp {
                                                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);
+                                       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);
+                                       if (result_type == null)
+                                               return v;
+                                       else
+                                               return new EnumConstant (v, result_type);
                                }
                                break;
 
@@ -331,6 +397,26 @@ namespace Mono.CSharp {
                                                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);
+                                       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);
+                                       if (result_type == null)
+                                               return v;
+                                       else
+                                               return new EnumConstant (v, result_type);
                                }
                                break;
 
@@ -445,8 +531,19 @@ namespace Mono.CSharp {
                                                                         ((IntConstant) right).Value);
 
                                                result = new IntConstant (res);
+                                       } else if (left is DecimalConstant) {
+                                               decimal res;
+
+                                               if (ec.ConstantCheckState)
+                                                       res = checked (((DecimalConstant) left).Value +
+                                                               ((DecimalConstant) right).Value);
+                                               else
+                                                       res = unchecked (((DecimalConstant) left).Value +
+                                                               ((DecimalConstant) right).Value);
+
+                                               result = new DecimalConstant (res);
                                        } else {
-                                               throw new Exception ( "Unexepected input: " + left);
+                                               throw new Exception ( "Unexepected addition input: " + left);
                                        }
                                } catch (OverflowException){
                                        Error_CompileTimeOverflow (loc);
@@ -552,8 +649,19 @@ namespace Mono.CSharp {
                                                                         ((IntConstant) right).Value);
 
                                                result = new IntConstant (res);
+                                       } else if (left is DecimalConstant) {
+                                               decimal res;
+
+                                               if (ec.ConstantCheckState)
+                                                       res = checked (((DecimalConstant) left).Value -
+                                                               ((DecimalConstant) right).Value);
+                                               else
+                                                       res = unchecked (((DecimalConstant) left).Value -
+                                                               ((DecimalConstant) right).Value);
+
+                                               return new DecimalConstant (res);
                                        } else {
-                                               throw new Exception ( "Unexepected input: " + left);
+                                               throw new Exception ( "Unexepected subtraction input: " + left);
                                        }
                                } catch (OverflowException){
                                        Error_CompileTimeOverflow (loc);
@@ -574,10 +682,10 @@ namespace Mono.CSharp {
                                                
                                                if (ec.ConstantCheckState)
                                                        res = checked (((DoubleConstant) left).Value *
-                                                                      ((DoubleConstant) right).Value);
+                                                               ((DoubleConstant) right).Value);
                                                else
                                                        res = unchecked (((DoubleConstant) left).Value *
-                                                                        ((DoubleConstant) right).Value);
+                                                               ((DoubleConstant) right).Value);
                                                
                                                return new DoubleConstant (res);
                                        } else if (left is FloatConstant){
@@ -585,10 +693,10 @@ namespace Mono.CSharp {
                                                
                                                if (ec.ConstantCheckState)
                                                        res = checked (((FloatConstant) left).Value *
-                                                                      ((FloatConstant) right).Value);
+                                                               ((FloatConstant) right).Value);
                                                else
                                                        res = unchecked (((FloatConstant) left).Value *
-                                                                        ((FloatConstant) right).Value);
+                                                               ((FloatConstant) right).Value);
                                                
                                                return new FloatConstant (res);
                                        } else if (left is ULongConstant){
@@ -596,10 +704,10 @@ namespace Mono.CSharp {
                                                
                                                if (ec.ConstantCheckState)
                                                        res = checked (((ULongConstant) left).Value *
-                                                                      ((ULongConstant) right).Value);
+                                                               ((ULongConstant) right).Value);
                                                else
                                                        res = unchecked (((ULongConstant) left).Value *
-                                                                        ((ULongConstant) right).Value);
+                                                               ((ULongConstant) right).Value);
                                                
                                                return new ULongConstant (res);
                                        } else if (left is LongConstant){
@@ -607,10 +715,10 @@ namespace Mono.CSharp {
                                                
                                                if (ec.ConstantCheckState)
                                                        res = checked (((LongConstant) left).Value *
-                                                                      ((LongConstant) right).Value);
+                                                               ((LongConstant) right).Value);
                                                else
                                                        res = unchecked (((LongConstant) left).Value *
-                                                                        ((LongConstant) right).Value);
+                                                               ((LongConstant) right).Value);
                                                
                                                return new LongConstant (res);
                                        } else if (left is UIntConstant){
@@ -618,10 +726,10 @@ namespace Mono.CSharp {
                                                
                                                if (ec.ConstantCheckState)
                                                        res = checked (((UIntConstant) left).Value *
-                                                                      ((UIntConstant) right).Value);
+                                                               ((UIntConstant) right).Value);
                                                else
                                                        res = unchecked (((UIntConstant) left).Value *
-                                                                        ((UIntConstant) right).Value);
+                                                               ((UIntConstant) right).Value);
                                                
                                                return new UIntConstant (res);
                                        } else if (left is IntConstant){
@@ -629,14 +737,25 @@ namespace Mono.CSharp {
 
                                                if (ec.ConstantCheckState)
                                                        res = checked (((IntConstant) left).Value *
-                                                                      ((IntConstant) right).Value);
+                                                               ((IntConstant) right).Value);
                                                else
                                                        res = unchecked (((IntConstant) left).Value *
-                                                                        ((IntConstant) right).Value);
+                                                               ((IntConstant) right).Value);
 
                                                return new IntConstant (res);
+                                       } else if (left is DecimalConstant) {
+                                               decimal res;
+
+                                               if (ec.ConstantCheckState)
+                                                       res = checked (((DecimalConstant) left).Value *
+                                                               ((DecimalConstant) right).Value);
+                                               else
+                                                       res = unchecked (((DecimalConstant) left).Value *
+                                                               ((DecimalConstant) right).Value);
+
+                                               return new DecimalConstant (res);
                                        } else {
-                                               throw new Exception ( "Unexepected input: " + left);
+                                               throw new Exception ( "Unexepected multiply input: " + left);
                                        }
                                } catch (OverflowException){
                                        Error_CompileTimeOverflow (loc);
@@ -654,10 +773,10 @@ namespace Mono.CSharp {
                                                
                                                if (ec.ConstantCheckState)
                                                        res = checked (((DoubleConstant) left).Value /
-                                                                      ((DoubleConstant) right).Value);
+                                                               ((DoubleConstant) right).Value);
                                                else
                                                        res = unchecked (((DoubleConstant) left).Value /
-                                                                        ((DoubleConstant) right).Value);
+                                                               ((DoubleConstant) right).Value);
                                                
                                                return new DoubleConstant (res);
                                        } else if (left is FloatConstant){
@@ -665,10 +784,10 @@ namespace Mono.CSharp {
                                                
                                                if (ec.ConstantCheckState)
                                                        res = checked (((FloatConstant) left).Value /
-                                                                      ((FloatConstant) right).Value);
+                                                               ((FloatConstant) right).Value);
                                                else
                                                        res = unchecked (((FloatConstant) left).Value /
-                                                                        ((FloatConstant) right).Value);
+                                                               ((FloatConstant) right).Value);
                                                
                                                return new FloatConstant (res);
                                        } else if (left is ULongConstant){
@@ -676,10 +795,10 @@ namespace Mono.CSharp {
                                                
                                                if (ec.ConstantCheckState)
                                                        res = checked (((ULongConstant) left).Value /
-                                                                      ((ULongConstant) right).Value);
+                                                               ((ULongConstant) right).Value);
                                                else
                                                        res = unchecked (((ULongConstant) left).Value /
-                                                                        ((ULongConstant) right).Value);
+                                                               ((ULongConstant) right).Value);
                                                
                                                return new ULongConstant (res);
                                        } else if (left is LongConstant){
@@ -687,10 +806,10 @@ namespace Mono.CSharp {
                                                
                                                if (ec.ConstantCheckState)
                                                        res = checked (((LongConstant) left).Value /
-                                                                      ((LongConstant) right).Value);
+                                                               ((LongConstant) right).Value);
                                                else
                                                        res = unchecked (((LongConstant) left).Value /
-                                                                        ((LongConstant) right).Value);
+                                                               ((LongConstant) right).Value);
                                                
                                                return new LongConstant (res);
                                        } else if (left is UIntConstant){
@@ -698,10 +817,10 @@ namespace Mono.CSharp {
                                                
                                                if (ec.ConstantCheckState)
                                                        res = checked (((UIntConstant) left).Value /
-                                                                      ((UIntConstant) right).Value);
+                                                               ((UIntConstant) right).Value);
                                                else
                                                        res = unchecked (((UIntConstant) left).Value /
-                                                                        ((UIntConstant) right).Value);
+                                                               ((UIntConstant) right).Value);
                                                
                                                return new UIntConstant (res);
                                        } else if (left is IntConstant){
@@ -709,14 +828,25 @@ namespace Mono.CSharp {
 
                                                if (ec.ConstantCheckState)
                                                        res = checked (((IntConstant) left).Value /
-                                                                      ((IntConstant) right).Value);
+                                                               ((IntConstant) right).Value);
                                                else
                                                        res = unchecked (((IntConstant) left).Value /
-                                                                        ((IntConstant) right).Value);
+                                                               ((IntConstant) right).Value);
 
                                                return new IntConstant (res);
+                                       } else if (left is DecimalConstant) {
+                                               decimal res;
+
+                                               if (ec.ConstantCheckState)
+                                                       res = checked (((DecimalConstant) left).Value /
+                                                               ((DecimalConstant) right).Value);
+                                               else
+                                                       res = unchecked (((DecimalConstant) left).Value /
+                                                               ((DecimalConstant) right).Value);
+
+                                               return new DecimalConstant (res);
                                        } else {
-                                               throw new Exception ( "Unexepected input: " + left);
+                                               throw new Exception ( "Unexepected division input: " + left);
                                        }
                                } catch (OverflowException){
                                        Error_CompileTimeOverflow (loc);
@@ -800,7 +930,7 @@ namespace Mono.CSharp {
 
                                                return new IntConstant (res);
                                        } else {
-                                               throw new Exception ( "Unexepected input: " + left);
+                                               throw new Exception ( "Unexepected modulus input: " + left);
                                        }
                                } catch (DivideByZeroException){
                                        Report.Error (020, loc, "Division by constant zero");
@@ -892,13 +1022,26 @@ namespace Mono.CSharp {
                                                ((BoolConstant) right).Value);
                                
                                }
+                               if (left is NullLiteral){
+                                       if (right is NullLiteral)
+                                               return new BoolConstant (true);
+                                       else if (right is StringConstant)
+                                               return new BoolConstant (
+                                                       ((StringConstant) right).Value == null);
+                               } else if (right is NullLiteral){
+                                       if (left is NullLiteral)
+                                               return new BoolConstant (true);
+                                       else if (left is StringConstant)
+                                               return new BoolConstant (
+                                                       ((StringConstant) left).Value == null);
+                               }
                                if (left is StringConstant && right is StringConstant){
                                        return new BoolConstant (
                                                ((StringConstant) left).Value ==
                                                ((StringConstant) right).Value);
                                        
                                }
-                               
+
                                DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
                                if (left == null || right == null)
                                        return null;
@@ -933,6 +1076,19 @@ namespace Mono.CSharp {
                                                ((BoolConstant) left).Value !=
                                                ((BoolConstant) right).Value);
                                }
+                               if (left is NullLiteral){
+                                       if (right is NullLiteral)
+                                               return new BoolConstant (false);
+                                       else if (right is StringConstant)
+                                               return new BoolConstant (
+                                                       ((StringConstant) right).Value != null);
+                               } else if (right is NullLiteral){
+                                       if (left is NullLiteral)
+                                               return new BoolConstant (false);
+                                       else if (left is StringConstant)
+                                               return new BoolConstant (
+                                                       ((StringConstant) left).Value != null);
+                               }
                                if (left is StringConstant && right is StringConstant){
                                        return new BoolConstant (
                                                ((StringConstant) left).Value !=