Fix #73038.
[mono.git] / mcs / mcs / constant.cs
old mode 100755 (executable)
new mode 100644 (file)
index 0f154fe..5bf0335
@@ -17,12 +17,6 @@ namespace Mono.CSharp {
        ///   Base class for constants and literals.
        /// </summary>
        public abstract class Constant : Expression {
-
-               protected Constant ()
-               {
-                       eclass = ExprClass.Value;
-               }
-
                /// <remarks>
                ///   This is different from ToString in that ToString
                ///   is supposed to be there for debugging purposes,
@@ -68,7 +62,7 @@ namespace Mono.CSharp {
                        DoubleConstant c = ConvertToDouble ();
 
                        if (c == null)
-                               Error_CannotConvertImplicit (loc, Type, TypeManager.double_type);
+                               Convert.Error_CannotImplicitConversion (loc, Type, TypeManager.double_type);
 
                        return c;
                }
@@ -78,7 +72,7 @@ namespace Mono.CSharp {
                        FloatConstant c = ConvertToFloat ();
 
                        if (c == null)
-                               Error_CannotConvertImplicit (loc, Type, TypeManager.float_type);
+                               Convert.Error_CannotImplicitConversion (loc, Type, TypeManager.float_type);
 
                        return c;
                }
@@ -88,7 +82,7 @@ namespace Mono.CSharp {
                        ULongConstant c = ConvertToULong ();
 
                        if (c == null)
-                               Error_CannotConvertImplicit (loc, Type, TypeManager.uint64_type);
+                               Convert.Error_CannotImplicitConversion (loc, Type, TypeManager.uint64_type);
 
                        return c;
                }
@@ -98,7 +92,7 @@ namespace Mono.CSharp {
                        LongConstant c = ConvertToLong ();
 
                        if (c == null)
-                               Error_CannotConvertImplicit (loc, Type, TypeManager.int64_type);
+                               Convert.Error_CannotImplicitConversion (loc, Type, TypeManager.int64_type);
 
                        return c;
                }
@@ -108,7 +102,7 @@ namespace Mono.CSharp {
                        UIntConstant c = ConvertToUInt ();
 
                        if (c == null)
-                               Error_CannotConvertImplicit (loc, Type, TypeManager.uint32_type);
+                               Convert.Error_CannotImplicitConversion (loc, Type, TypeManager.uint32_type);
 
                        return c;
                }
@@ -118,10 +112,25 @@ namespace Mono.CSharp {
                        IntConstant c = ConvertToInt ();
 
                        if (c == null)
-                               Error_CannotConvertImplicit (loc, Type, TypeManager.int32_type);
+                               Convert.Error_CannotImplicitConversion (loc, Type, TypeManager.int32_type);
+
+                       return c;
+               }
+
+               public DecimalConstant ToDecimal (Location loc)
+               {
+                       DecimalConstant c = ConvertToDecimal ();
+
+                       if (c == null)
+                               Convert.Error_CannotConvertType (loc, Type, TypeManager.decimal_type);
 
                        return c;
                }
+
+               public virtual DecimalConstant ConvertToDecimal ()
+               {
+                       return null;
+               }
                
                public virtual DoubleConstant ConvertToDouble ()
                {
@@ -152,6 +161,22 @@ namespace Mono.CSharp {
                {
                        return null;
                }
+               
+               public abstract bool IsDefaultValue {
+                       get;
+               }
+
+               public abstract bool IsNegative {
+                       get;
+               }
+
+               //
+               // Returns true iff 1) the stack type of this is one of Object, 
+               // int32, int64 and 2) this == 0 or this == null.
+               //
+               public virtual bool IsZeroInteger {
+                       get { return false; }
+               }
        }
        
        public class BoolConstant : Constant {
@@ -160,6 +185,7 @@ namespace Mono.CSharp {
                public BoolConstant (bool val)
                {
                        type = TypeManager.bool_type;
+                       eclass = ExprClass.Value;
 
                        Value = val;
                }
@@ -182,6 +208,22 @@ namespace Mono.CSharp {
                        else
                                ec.ig.Emit (OpCodes.Ldc_I4_0);
                }
+       
+               public override bool IsDefaultValue {
+                       get {
+                               return !Value;
+                       }
+               }
+
+               public override bool IsNegative {
+                       get {
+                               return false;
+                       }
+               }
+       
+               public override bool IsZeroInteger {
+                       get { return Value == false; }
+               }
        }
 
        public class ByteConstant : Constant {
@@ -190,6 +232,7 @@ namespace Mono.CSharp {
                public ByteConstant (byte v)
                {
                        type = TypeManager.byte_type;
+                       eclass = ExprClass.Value;
                        Value = v;
                }
 
@@ -237,6 +280,22 @@ namespace Mono.CSharp {
                {
                        return new IntConstant (Value);
                }
+
+               public override bool IsDefaultValue {
+                       get {
+                               return Value == 0;
+                       }
+               }
+
+               public override bool IsNegative {
+                       get {
+                               return false;
+                       }
+               }
+
+               public override bool IsZeroInteger {
+                       get { return Value == 0; }
+               }
        }
 
        public class CharConstant : Constant {
@@ -245,6 +304,7 @@ namespace Mono.CSharp {
                public CharConstant (char v)
                {
                        type = TypeManager.char_type;
+                       eclass = ExprClass.Value;
                        Value = v;
                }
 
@@ -321,6 +381,22 @@ namespace Mono.CSharp {
                {
                        return new IntConstant (Value);
                }
+               
+               public override bool IsDefaultValue {
+                       get {
+                               return Value == 0;
+                       }
+               }
+
+               public override bool IsNegative {
+                       get {
+                               return false;
+                       }
+               }
+
+               public override bool IsZeroInteger {
+                       get { return Value == '\0'; }
+               }
        }
 
        public class SByteConstant : Constant {
@@ -329,6 +405,7 @@ namespace Mono.CSharp {
                public SByteConstant (sbyte v)
                {
                        type = TypeManager.sbyte_type;
+                       eclass = ExprClass.Value;
                        Value = v;
                }
 
@@ -379,6 +456,22 @@ namespace Mono.CSharp {
                {
                        return new IntConstant (Value);
                }
+
+               public override bool IsDefaultValue {
+                       get {
+                               return Value == 0;
+                       }
+               }
+
+               public override bool IsNegative {
+                       get {
+                               return Value < 0;
+                       }
+               }
+               
+               public override bool IsZeroInteger {
+                       get { return Value == 0; }
+               }
        }
 
        public class ShortConstant : Constant {
@@ -387,6 +480,7 @@ namespace Mono.CSharp {
                public ShortConstant (short v)
                {
                        type = TypeManager.short_type;
+                       eclass = ExprClass.Value;
                        Value = v;
                }
 
@@ -434,6 +528,22 @@ namespace Mono.CSharp {
                {
                        return new IntConstant (Value);
                }
+
+               public override bool IsDefaultValue {
+                       get {
+                               return Value == 0;
+                       }
+               }
+               
+               public override bool IsZeroInteger {
+                       get { return Value == 0; }
+               }
+
+               public override bool IsNegative {
+                       get {
+                               return Value < 0;
+                       }
+               }
        }
 
        public class UShortConstant : Constant {
@@ -442,6 +552,7 @@ namespace Mono.CSharp {
                public UShortConstant (ushort v)
                {
                        type = TypeManager.ushort_type;
+                       eclass = ExprClass.Value;
                        Value = v;
                }
 
@@ -489,6 +600,22 @@ namespace Mono.CSharp {
                {
                        return new IntConstant (Value);
                }
+       
+               public override bool IsDefaultValue {
+                       get {
+                               return Value == 0;
+                       }
+               }
+
+               public override bool IsNegative {
+                       get {
+                               return false;
+                       }
+               }
+       
+               public override bool IsZeroInteger {
+                       get { return Value == 0; }
+               }
        }
 
        public class IntConstant : Constant {
@@ -497,6 +624,7 @@ namespace Mono.CSharp {
                public IntConstant (int v)
                {
                        type = TypeManager.int32_type;
+                       eclass = ExprClass.Value;
                        Value = v;
                }
 
@@ -567,6 +695,11 @@ namespace Mono.CSharp {
                        return Value;
                }
 
+               public override DecimalConstant ConvertToDecimal()
+               {
+                       return new DecimalConstant (Value);
+               }
+
                public override DoubleConstant ConvertToDouble ()
                {
                        return new DoubleConstant (Value);
@@ -602,6 +735,22 @@ namespace Mono.CSharp {
                {
                        return this;
                }
+
+               public override bool IsDefaultValue {
+                       get {
+                               return Value == 0;
+                       }
+               }
+               
+               public override bool IsNegative {
+                       get {
+                               return Value < 0;
+                       }
+               }
+
+               public override bool IsZeroInteger {
+                       get { return Value == 0; }
+               }
        }
 
        public class UIntConstant : Constant {
@@ -610,6 +759,7 @@ namespace Mono.CSharp {
                public UIntConstant (uint v)
                {
                        type = TypeManager.uint32_type;
+                       eclass = ExprClass.Value;
                        Value = v;
                }
 
@@ -657,6 +807,22 @@ namespace Mono.CSharp {
                {
                        return null;
                }
+               
+               public override bool IsDefaultValue {
+                       get {
+                               return Value == 0;
+                       }
+               }
+
+               public override bool IsNegative {
+                       get {
+                               return false;
+                       }
+               }
+
+               public override bool IsZeroInteger {
+                       get { return Value == 0; }
+               }
        }
 
        public class LongConstant : Constant {
@@ -665,6 +831,7 @@ namespace Mono.CSharp {
                public LongConstant (long v)
                {
                        type = TypeManager.int64_type;
+                       eclass = ExprClass.Value;
                        Value = v;
                }
 
@@ -677,7 +844,12 @@ namespace Mono.CSharp {
 
                static public void EmitLong (ILGenerator ig, long l)
                {
-                       ig.Emit (OpCodes.Ldc_I8, l);
+                       if ((l >> 32) == 0){
+                               IntLiteral.EmitInt (ig, unchecked ((int) l));
+                               ig.Emit (OpCodes.Conv_U8);
+                       } else {
+                               ig.Emit (OpCodes.Ldc_I8, l);
+                       }
                }
 
                public override string AsString ()
@@ -722,6 +894,22 @@ namespace Mono.CSharp {
                {
                        return null;
                }
+               
+               public override bool IsDefaultValue {
+                       get {
+                               return Value == 0;
+                       }
+               }
+
+               public override bool IsNegative {
+                       get {
+                               return Value < 0;
+                       }
+               }
+
+               public override bool IsZeroInteger {
+                       get { return Value == 0; }
+               }
        }
 
        public class ULongConstant : Constant {
@@ -730,6 +918,7 @@ namespace Mono.CSharp {
                public ULongConstant (ulong v)
                {
                        type = TypeManager.uint64_type;
+                       eclass = ExprClass.Value;
                        Value = v;
                }
 
@@ -779,6 +968,22 @@ namespace Mono.CSharp {
                {
                        return null;
                }
+
+               public override bool IsDefaultValue {
+                       get {
+                               return Value == 0;
+                       }
+               }
+
+               public override bool IsNegative {
+                       get {
+                               return false;
+                       }
+               }
+
+               public override bool IsZeroInteger {
+                       get { return Value == 0; }
+               }
        }
 
        public class FloatConstant : Constant {
@@ -787,6 +992,7 @@ namespace Mono.CSharp {
                public FloatConstant (float v)
                {
                        type = TypeManager.float_type;
+                       eclass = ExprClass.Value;
                        Value = v;
                }
 
@@ -829,6 +1035,18 @@ namespace Mono.CSharp {
                {
                        return null;
                }
+
+               public override bool IsDefaultValue {
+                       get {
+                               return Value == 0;
+                       }
+               }
+
+               public override bool IsNegative {
+                       get {
+                               return Value < 0;
+                       }
+               }
        }
 
        public class DoubleConstant : Constant {
@@ -837,6 +1055,7 @@ namespace Mono.CSharp {
                public DoubleConstant (double v)
                {
                        type = TypeManager.double_type;
+                       eclass = ExprClass.Value;
                        Value = v;
                }
 
@@ -884,6 +1103,18 @@ namespace Mono.CSharp {
                {
                        return null;
                }
+
+               public override bool IsDefaultValue {
+                       get {
+                               return Value == 0;
+                       }
+               }
+
+               public override bool IsNegative {
+                       get {
+                               return Value < 0;
+                       }
+               }
        }
 
        public class DecimalConstant : Constant {
@@ -892,6 +1123,7 @@ namespace Mono.CSharp {
                public DecimalConstant (decimal d)
                {
                        type = TypeManager.decimal_type;
+                       eclass = ExprClass.Value;
                        Value = d;
                }
 
@@ -907,7 +1139,47 @@ namespace Mono.CSharp {
 
                public override void Emit (EmitContext ec)
                {
-                       throw new Exception ("Implement me");
+                       ILGenerator ig = ec.ig;
+
+                       int [] words = Decimal.GetBits (Value);
+                       int power = (words [3] >> 16) & 0xff;
+
+                       if (power == 0 && Value <= int.MaxValue && Value >= int.MinValue)
+                       {
+                               IntConstant.EmitInt (ig, (int)Value);
+                               ig.Emit (OpCodes.Newobj, TypeManager.void_decimal_ctor_int_arg);
+                               return;
+                       }
+
+                       
+                       //
+                       // FIXME: we could optimize this, and call a better 
+                       // constructor
+                       //
+
+                       IntConstant.EmitInt (ig, words [0]);
+                       IntConstant.EmitInt (ig, words [1]);
+                       IntConstant.EmitInt (ig, words [2]);
+
+                       // sign
+                       IntConstant.EmitInt (ig, words [3] >> 31);
+
+                       // power
+                       IntConstant.EmitInt (ig, power);
+
+                       ig.Emit (OpCodes.Newobj, TypeManager.void_decimal_ctor_five_args);
+               }
+
+               public override bool IsDefaultValue {
+                       get {
+                               return Value == 0;
+                       }
+               }
+
+               public override bool IsNegative {
+                       get {
+                               return Value < 0;
+                       }
                }
        }
 
@@ -917,6 +1189,7 @@ namespace Mono.CSharp {
                public StringConstant (string s)
                {
                        type = TypeManager.string_type;
+                       eclass = ExprClass.Value;
                        Value = s;
                }
 
@@ -933,7 +1206,22 @@ namespace Mono.CSharp {
                
                public override void Emit (EmitContext ec)
                {
-                       ec.ig.Emit (OpCodes.Ldstr, Value);
+                       if (Value == null)
+                               ec.ig.Emit (OpCodes.Ldnull);
+                       else
+                               ec.ig.Emit (OpCodes.Ldstr, Value);
+               }
+
+               public override bool IsDefaultValue {
+                       get {
+                               return Value == null;
+                       }
+               }
+
+               public override bool IsNegative {
+                       get {
+                               return false;
+                       }
                }
        }