X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;ds=sidebyside;f=mcs%2Fmcs%2Fconstant.cs;h=5dae2a6a55050d96ee35abcaf159addffbb21001;hb=bb7dfed5ae69b716b4f4c2458a78fcb704fa78d0;hp=76c2c5667a8574a363f163ea62e0f84844823968;hpb=f11aa9faf50ec2997ea88350885a0d10ec0d815c;p=mono.git diff --git a/mcs/mcs/constant.cs b/mcs/mcs/constant.cs index 76c2c5667a8..5dae2a6a550 100644 --- a/mcs/mcs/constant.cs +++ b/mcs/mcs/constant.cs @@ -39,6 +39,23 @@ namespace Mono.CSharp { return this.GetType ().Name + " (" + AsString () + ")"; } + public override bool GetAttributableValue (Type value_type, out object value) + { + if (value_type == TypeManager.object_type) { + value = GetTypedValue (); + return true; + } + + Constant c = ImplicitConversionRequired (value_type, loc); + if (c == null) { + value = null; + return false; + } + + value = c.GetTypedValue (); + return true; + } + /// /// This is used to obtain the actual value of the literal /// cast into an object. @@ -58,182 +75,86 @@ namespace Mono.CSharp { return this; } - // - // The various ToXXXX conversion functions are used by the constant - // folding evaluator. A null value is returned if the conversion is - // not possible. - // - // Note: not all the patterns for catching `implicit_conv' are the same. - // some implicit conversions can never be performed between two types - // even if the conversion would be lossless (for example short to uint), - // but some conversions are explicitly permitted by the standard provided - // that there will be no loss of information (for example, int to uint). - // - public DoubleConstant ToDouble (Location loc) - { - DoubleConstant c = ConvertToDouble (); - - if (c == null) - Error_ValueCannotBeConverted (loc, TypeManager.double_type, false); - - return c; - } - - public FloatConstant ToFloat (Location loc) - { - FloatConstant c = ConvertToFloat (); - - if (c == null) - Error_ValueCannotBeConverted (loc, TypeManager.float_type, false); - - return c; - } - - public ULongConstant ToULong (Location loc) - { - ULongConstant c = ConvertToULong (); - - if (c == null) - Error_ValueCannotBeConverted (loc, TypeManager.uint64_type, false); - - return c; - } - - public LongConstant ToLong (Location loc) - { - LongConstant c = ConvertToLong (); - - if (c == null) - Error_ValueCannotBeConverted (loc, TypeManager.int64_type, false); - - return c; - } - - public UIntConstant ToUInt (Location loc) - { - UIntConstant c = ConvertToUInt (); - - if (c == null) - Error_ValueCannotBeConverted (loc, TypeManager.uint32_type, false); - - return c; - } - - public IntConstant ToInt (Location loc) + public Constant ImplicitConversionRequired (Type type, Location loc) { - IntConstant c = ConvertToInt (); - + Constant c = ConvertImplicitly (type); if (c == null) - Error_ValueCannotBeConverted (loc, TypeManager.int32_type, false); - + Error_ValueCannotBeConverted (null, loc, type, false); return c; } - public DecimalConstant ToDecimal (Location loc) + public virtual Constant ConvertImplicitly (Type type) { - DecimalConstant c = ConvertToDecimal (); - - if (c == null) - Error_ValueCannotBeConverted (loc, TypeManager.decimal_type, false); - - return c; - } - - public virtual Constant ToType (Type type, Location loc) - { - if (Type == type) - return this; - - if (type == TypeManager.object_type) + if (this.type == type) return this; - if (!Convert.ImplicitStandardConversionExists (Convert.ConstantEC, this, type)){ - Error_ValueCannotBeConverted (loc, type, false); + if (Convert.ImplicitNumericConversion (this, type) == null) return null; - } - - // Special-case: The 0 literal can be converted to an enum value, - // and ImplicitStandardConversionExists will return true in that case. - if (IsZeroInteger && Type == TypeManager.int32_type && TypeManager.IsEnumType (type)) { - return new EnumConstant (this, type); - } bool fail; object constant_value = TypeManager.ChangeType (GetValue (), type, out fail); if (fail){ - Error_ValueCannotBeConverted (loc, type, false); - // // We should always catch the error before this is ever // reached, by calling Convert.ImplicitStandardConversionExists // - throw new Exception ( - String.Format ("LookupConstantValue: This should never be reached {0} {1}", Type, type)); - } - - Constant retval; - if (type == TypeManager.int32_type) - retval = new IntConstant ((int) constant_value, loc); - else if (type == TypeManager.uint32_type) - retval = new UIntConstant ((uint) constant_value, loc); - else if (type == TypeManager.int64_type) - retval = new LongConstant ((long) constant_value, loc); - else if (type == TypeManager.uint64_type) - retval = new ULongConstant ((ulong) constant_value, loc); - else if (type == TypeManager.float_type) - retval = new FloatConstant ((float) constant_value, loc); - else if (type == TypeManager.double_type) - retval = new DoubleConstant ((double) constant_value, loc); - else if (type == TypeManager.string_type) - retval = new StringConstant ((string) constant_value, loc); - else if (type == TypeManager.short_type) - retval = new ShortConstant ((short) constant_value, loc); - else if (type == TypeManager.ushort_type) - retval = new UShortConstant ((ushort) constant_value, loc); - else if (type == TypeManager.sbyte_type) - retval = new SByteConstant ((sbyte) constant_value, loc); - else if (type == TypeManager.byte_type) - retval = new ByteConstant ((byte) constant_value, loc); - else if (type == TypeManager.char_type) - retval = new CharConstant ((char) constant_value, loc); - else if (type == TypeManager.bool_type) - retval = new BoolConstant ((bool) constant_value, loc); - else if (type == TypeManager.decimal_type) - retval = new DecimalConstant ((decimal) constant_value, loc); - else - throw new Exception ("LookupConstantValue: Unhandled constant type: " + type); - - return retval; - } - - protected void CheckRange (EmitContext ec, ulong value, Type type, ulong max) - { - if (!ec.ConstantCheckState) - return; - - if (value > max) - throw new OverflowException (); - } - - protected void CheckRange (EmitContext ec, double value, Type type, long min, long max) - { - if (!ec.ConstantCheckState) - return; - - if (((value < min) || (value > max))) - throw new OverflowException (); - } - - protected void CheckUnsigned (EmitContext ec, long value, Type type) - { - if (!ec.ConstantCheckState) - return; - - if (value < 0) - throw new OverflowException (); + throw new InternalErrorException ("Missing constant conversion between `{0}' and `{1}'", + TypeManager.CSharpName (Type), TypeManager.CSharpName (type)); + } + + return CreateConstant (type, constant_value, loc); + } + + /// Returns a constant instance based on Type + /// The returned value is already resolved. + public static Constant CreateConstant (Type t, object v, Location loc) + { + if (t == TypeManager.int32_type) + return new IntConstant ((int) v, loc); + if (t == TypeManager.string_type) + return new StringConstant ((string) v, loc); + if (t == TypeManager.uint32_type) + return new UIntConstant ((uint) v, loc); + if (t == TypeManager.int64_type) + return new LongConstant ((long) v, loc); + if (t == TypeManager.uint64_type) + return new ULongConstant ((ulong) v, loc); + if (t == TypeManager.float_type) + return new FloatConstant ((float) v, loc); + if (t == TypeManager.double_type) + return new DoubleConstant ((double) v, loc); + if (t == TypeManager.short_type) + return new ShortConstant ((short)v, loc); + if (t == TypeManager.ushort_type) + return new UShortConstant ((ushort)v, loc); + if (t == TypeManager.sbyte_type) + return new SByteConstant ((sbyte)v, loc); + if (t == TypeManager.byte_type) + return new ByteConstant ((byte)v, loc); + if (t == TypeManager.char_type) + return new CharConstant ((char)v, loc); + if (t == TypeManager.bool_type) + return new BoolConstant ((bool) v, loc); + if (t == TypeManager.decimal_type) + return new DecimalConstant ((decimal) v, loc); + if (TypeManager.IsEnumType (t)) { + Type real_type = TypeManager.TypeToCoreType (v.GetType ()); + if (real_type == t) + real_type = System.Enum.GetUnderlyingType (real_type); + return new EnumConstant (CreateConstant (real_type, v, loc), t); + } + if (v == null && !TypeManager.IsValueType (t)) + return new EmptyConstantCast (new NullConstant (loc), t); + + throw new Exception ("Unknown type for constant (" + t + + "), details: " + v); } - - public abstract Constant Reduce (EmitContext ec, Type target_type); + /// + /// Maybe ConvertTo name is better. It tries to convert `this' constant to target_type. + /// It throws OverflowException + /// + // DON'T CALL THIS METHOD DIRECTLY AS IT DOES NOT HANDLE ENUMS + public abstract Constant ConvertExplicitly (bool in_checked_context, Type target_type); /// /// Attempts to do a compile-time folding of a constant cast. @@ -241,13 +162,11 @@ namespace Mono.CSharp { public Constant TryReduce (EmitContext ec, Type target_type, Location loc) { try { - return TryReduce (ec, target_type); + return TryReduce (ec, target_type); } catch (OverflowException) { - if (ec.ConstantCheckState) { - Report.Error (221, loc, "Constant value `{0}' cannot be converted to a `{1}' (use `unchecked' syntax to override)", - GetValue ().ToString (), TypeManager.CSharpName (target_type)); - } + Report.Error (221, loc, "Constant value `{0}' cannot be converted to a `{1}' (use `unchecked' syntax to override)", + GetValue ().ToString (), TypeManager.CSharpName (target_type)); return null; } } @@ -265,47 +184,23 @@ namespace Mono.CSharp { return new EnumConstant (c, target_type); } - return Reduce (ec, target_type); + return ConvertExplicitly (ec.ConstantCheckState, target_type); } - - public virtual DecimalConstant ConvertToDecimal () - { - return null; - } + public abstract Constant Increment (); - public virtual DoubleConstant ConvertToDouble () - { - return null; - } - - public virtual FloatConstant ConvertToFloat () - { - return null; - } - - public virtual ULongConstant ConvertToULong () - { - return null; - } - - public virtual LongConstant ConvertToLong () + /// + /// Need to pass type as the constant can require a boxing + /// and in such case no optimization is possible + /// + public bool IsDefaultInitializer (Type type) { - return null; - } + if (type == Type) + return IsDefaultValue; - public virtual UIntConstant ConvertToUInt () - { - return null; + return Type == TypeManager.null_type; } - public virtual IntConstant ConvertToInt () - { - return null; - } - - public abstract Constant Increment (); - public abstract bool IsDefaultValue { get; } @@ -321,6 +216,31 @@ namespace Mono.CSharp { public virtual bool IsZeroInteger { get { return false; } } + + protected override void CloneTo (CloneContext clonectx, Expression target) + { + // CloneTo: Nothing, we do not keep any state on this expression + } + } + + public abstract class IntegralConstant : Constant { + protected IntegralConstant (Location loc) : + base (loc) + { + } + + public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl) + { + try { + ConvertExplicitly (true, target); + base.Error_ValueCannotBeConverted (ec, loc, target, expl); + } + catch + { + Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'", + GetValue ().ToString (), TypeManager.CSharpName (target)); + } + } } public class BoolConstant : Constant { @@ -375,14 +295,14 @@ namespace Mono.CSharp { get { return Value == false; } } - public override Constant Reduce (EmitContext ec, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, Type target_type) { return null; } } - public class ByteConstant : Constant { + public class ByteConstant : IntegralConstant { public readonly byte Value; public ByteConstant (byte v, Location loc): @@ -408,36 +328,6 @@ namespace Mono.CSharp { return Value; } - public override DoubleConstant ConvertToDouble () - { - return new DoubleConstant (Value, loc); - } - - public override FloatConstant ConvertToFloat () - { - return new FloatConstant (Value, loc); - } - - public override ULongConstant ConvertToULong () - { - return new ULongConstant (Value, loc); - } - - public override LongConstant ConvertToLong () - { - return new LongConstant (Value, loc); - } - - public override UIntConstant ConvertToUInt () - { - return new UIntConstant (Value, loc); - } - - public override IntConstant ConvertToInt () - { - return new IntConstant (Value, loc); - } - public override Constant Increment () { return new ByteConstant (checked ((byte)(Value + 1)), loc); @@ -459,10 +349,13 @@ namespace Mono.CSharp { get { return Value == 0; } } - public override Constant Reduce (EmitContext ec, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, Type target_type) { if (target_type == TypeManager.sbyte_type) { - CheckRange (ec, Value, target_type, SByte.MinValue, SByte.MaxValue); + if (in_checked_context){ + if (Value > SByte.MaxValue) + throw new OverflowException (); + } return new SByteConstant ((sbyte) Value, Location); } if (target_type == TypeManager.short_type) @@ -546,36 +439,6 @@ namespace Mono.CSharp { return Value; } - public override DoubleConstant ConvertToDouble () - { - return new DoubleConstant (Value, loc); - } - - public override FloatConstant ConvertToFloat () - { - return new FloatConstant (Value, loc); - } - - public override ULongConstant ConvertToULong () - { - return new ULongConstant (Value, loc); - } - - public override LongConstant ConvertToLong () - { - return new LongConstant (Value, loc); - } - - public override UIntConstant ConvertToUInt () - { - return new UIntConstant (Value, loc); - } - - public override IntConstant ConvertToInt () - { - return new IntConstant (Value, loc); - } - public override Constant Increment () { return new CharConstant (checked ((char)(Value + 1)), loc); @@ -597,18 +460,27 @@ namespace Mono.CSharp { get { return Value == '\0'; } } - public override Constant Reduce (EmitContext ec, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, Type target_type) { if (target_type == TypeManager.byte_type) { - CheckRange (ec, Value, target_type, Byte.MinValue, Byte.MaxValue); + if (in_checked_context){ + if (Value < Byte.MinValue || Value > Byte.MaxValue) + throw new OverflowException (); + } return new ByteConstant ((byte) Value, Location); } if (target_type == TypeManager.sbyte_type) { - CheckRange (ec, Value, target_type, SByte.MinValue, SByte.MaxValue); + if (in_checked_context){ + if (Value > SByte.MaxValue) + throw new OverflowException (); + } return new SByteConstant ((sbyte) Value, Location); } if (target_type == TypeManager.short_type) { - CheckRange (ec, Value, target_type, Int16.MinValue, Int16.MaxValue); + if (in_checked_context){ + if (Value > Int16.MaxValue) + throw new OverflowException (); + } return new ShortConstant ((short) Value, Location); } if (target_type == TypeManager.int32_type) @@ -631,7 +503,7 @@ namespace Mono.CSharp { } - public class SByteConstant : Constant { + public class SByteConstant : IntegralConstant { public readonly sbyte Value; public SByteConstant (sbyte v, Location loc): @@ -657,39 +529,6 @@ namespace Mono.CSharp { return Value; } - public override DoubleConstant ConvertToDouble () - { - return new DoubleConstant (Value, loc); - } - - public override FloatConstant ConvertToFloat () - { - return new FloatConstant (Value, loc); - } - - public override ULongConstant ConvertToULong () - { - if (Value >= 0) - return new ULongConstant ((ulong) Value, loc); - - return null; - } - - public override LongConstant ConvertToLong () - { - return new LongConstant (Value, loc); - } - - public override UIntConstant ConvertToUInt () - { - return null; - } - - public override IntConstant ConvertToInt () - { - return new IntConstant (Value, loc); - } - public override Constant Increment () { return new SByteConstant (checked((sbyte)(Value + 1)), loc); @@ -711,26 +550,30 @@ namespace Mono.CSharp { get { return Value == 0; } } - public override Constant Reduce (EmitContext ec, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, Type target_type) { if (target_type == TypeManager.byte_type) { - CheckUnsigned (ec, Value, target_type); + if (in_checked_context && Value < 0) + throw new OverflowException (); return new ByteConstant ((byte) Value, Location); } if (target_type == TypeManager.short_type) return new ShortConstant ((short) Value, Location); if (target_type == TypeManager.ushort_type) { - CheckUnsigned (ec, Value, target_type); + if (in_checked_context && Value < 0) + throw new OverflowException (); return new UShortConstant ((ushort) Value, Location); } if (target_type == TypeManager.int32_type) return new IntConstant ((int) Value, Location); if (target_type == TypeManager.uint32_type) { - CheckUnsigned (ec, Value, target_type); + if (in_checked_context && Value < 0) + throw new OverflowException (); return new UIntConstant ((uint) Value, Location); } if (target_type == TypeManager.int64_type) return new LongConstant ((long) Value, Location); if (target_type == TypeManager.uint64_type) { - CheckUnsigned (ec, Value, target_type); + if (in_checked_context && Value < 0) + throw new OverflowException (); return new ULongConstant ((ulong) Value, Location); } if (target_type == TypeManager.float_type) @@ -738,7 +581,8 @@ namespace Mono.CSharp { if (target_type == TypeManager.double_type) return new DoubleConstant ((double) Value, Location); if (target_type == TypeManager.char_type) { - CheckUnsigned (ec, Value, target_type); + if (in_checked_context && Value < 0) + throw new OverflowException (); return new CharConstant ((char) Value, Location); } if (target_type == TypeManager.decimal_type) @@ -749,7 +593,7 @@ namespace Mono.CSharp { } - public class ShortConstant : Constant { + public class ShortConstant : IntegralConstant { public readonly short Value; public ShortConstant (short v, Location loc): @@ -775,36 +619,6 @@ namespace Mono.CSharp { return Value; } - public override DoubleConstant ConvertToDouble () - { - return new DoubleConstant (Value, loc); - } - - public override FloatConstant ConvertToFloat () - { - return new FloatConstant (Value, loc); - } - - public override ULongConstant ConvertToULong () - { - return null; - } - - public override LongConstant ConvertToLong () - { - return new LongConstant (Value, loc); - } - - public override UIntConstant ConvertToUInt () - { - return null; - } - - public override IntConstant ConvertToInt () - { - return new IntConstant (Value, loc); - } - public override Constant Increment () { return new ShortConstant (checked((short)(Value + 1)), loc); @@ -826,30 +640,40 @@ namespace Mono.CSharp { } } - public override Constant Reduce (EmitContext ec, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, Type target_type) { if (target_type == TypeManager.byte_type) { - CheckRange (ec, Value, target_type, Byte.MinValue, Byte.MaxValue); + if (in_checked_context){ + if (Value < Byte.MinValue || Value > Byte.MaxValue) + throw new OverflowException (); + } return new ByteConstant ((byte) Value, Location); } if (target_type == TypeManager.sbyte_type) { - CheckRange (ec, Value, target_type, SByte.MinValue, SByte.MaxValue); + if (in_checked_context){ + if (Value < SByte.MinValue || Value > SByte.MaxValue) + throw new OverflowException (); + } return new SByteConstant ((sbyte) Value, Location); } if (target_type == TypeManager.ushort_type) { - CheckUnsigned (ec, Value, target_type); + if (in_checked_context && Value < 0) + throw new OverflowException (); + return new UShortConstant ((ushort) Value, Location); } if (target_type == TypeManager.int32_type) return new IntConstant ((int) Value, Location); if (target_type == TypeManager.uint32_type) { - CheckUnsigned (ec, Value, target_type); + if (in_checked_context && Value < 0) + throw new OverflowException (); return new UIntConstant ((uint) Value, Location); } if (target_type == TypeManager.int64_type) return new LongConstant ((long) Value, Location); if (target_type == TypeManager.uint64_type) { - CheckUnsigned (ec, Value, target_type); + if (in_checked_context && Value < 0) + throw new OverflowException (); return new ULongConstant ((ulong) Value, Location); } if (target_type == TypeManager.float_type) @@ -857,7 +681,10 @@ namespace Mono.CSharp { if (target_type == TypeManager.double_type) return new DoubleConstant ((double) Value, Location); if (target_type == TypeManager.char_type) { - CheckRange (ec, Value, target_type, Char.MinValue, Char.MaxValue); + if (in_checked_context){ + if (Value < Char.MinValue) + throw new OverflowException (); + } return new CharConstant ((char) Value, Location); } if (target_type == TypeManager.decimal_type) @@ -868,7 +695,7 @@ namespace Mono.CSharp { } - public class UShortConstant : Constant { + public class UShortConstant : IntegralConstant { public readonly ushort Value; public UShortConstant (ushort v, Location loc): @@ -893,36 +720,6 @@ namespace Mono.CSharp { { return Value; } - - public override DoubleConstant ConvertToDouble () - { - return new DoubleConstant (Value, loc); - } - - public override FloatConstant ConvertToFloat () - { - return new FloatConstant (Value, loc); - } - - public override ULongConstant ConvertToULong () - { - return new ULongConstant (Value, loc); - } - - public override LongConstant ConvertToLong () - { - return new LongConstant (Value, loc); - } - - public override UIntConstant ConvertToUInt () - { - return new UIntConstant (Value, loc); - } - - public override IntConstant ConvertToInt () - { - return new IntConstant (Value, loc); - } public override Constant Increment () { @@ -945,18 +742,27 @@ namespace Mono.CSharp { get { return Value == 0; } } - public override Constant Reduce (EmitContext ec, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, Type target_type) { if (target_type == TypeManager.byte_type) { - CheckRange (ec, Value, target_type, Byte.MinValue, Byte.MaxValue); + if (in_checked_context){ + if (Value > Byte.MaxValue) + throw new OverflowException (); + } return new ByteConstant ((byte) Value, Location); } if (target_type == TypeManager.sbyte_type) { - CheckRange (ec, Value, target_type, SByte.MinValue, SByte.MaxValue); + if (in_checked_context){ + if (Value > SByte.MaxValue) + throw new OverflowException (); + } return new SByteConstant ((sbyte) Value, Location); } if (target_type == TypeManager.short_type) { - CheckRange (ec, Value, target_type, Int16.MinValue, Int16.MaxValue); + if (in_checked_context){ + if (Value > Int16.MaxValue) + throw new OverflowException (); + } return new ShortConstant ((short) Value, Location); } if (target_type == TypeManager.int32_type) @@ -972,7 +778,10 @@ namespace Mono.CSharp { if (target_type == TypeManager.double_type) return new DoubleConstant ((double) Value, Location); if (target_type == TypeManager.char_type) { - CheckRange (ec, Value, target_type, Char.MinValue, Char.MaxValue); + if (in_checked_context){ + if (Value > Char.MaxValue) + throw new OverflowException (); + } return new CharConstant ((char) Value, Location); } if (target_type == TypeManager.decimal_type) @@ -982,7 +791,7 @@ namespace Mono.CSharp { } } - public class IntConstant : Constant { + public class IntConstant : IntegralConstant { public readonly int Value; public IntConstant (int v, Location loc): @@ -1060,47 +869,6 @@ namespace Mono.CSharp { return Value; } - public override DecimalConstant ConvertToDecimal() - { - return new DecimalConstant (Value, loc); - } - - public override DoubleConstant ConvertToDouble () - { - return new DoubleConstant (Value, loc); - } - - public override FloatConstant ConvertToFloat () - { - return new FloatConstant (Value, loc); - } - - public override ULongConstant ConvertToULong () - { - if (Value < 0) - return null; - - return new ULongConstant ((ulong) Value, loc); - } - - public override LongConstant ConvertToLong () - { - return new LongConstant (Value, loc); - } - - public override UIntConstant ConvertToUInt () - { - if (Value < 0) - return null; - - return new UIntConstant ((uint) Value, loc); - } - - public override IntConstant ConvertToInt () - { - return this; - } - public override Constant Increment () { return new IntConstant (checked(Value + 1), loc); @@ -1122,32 +890,48 @@ namespace Mono.CSharp { get { return Value == 0; } } - public override Constant Reduce (EmitContext ec, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, Type target_type) { if (target_type == TypeManager.byte_type) { - CheckRange (ec, Value, target_type, Byte.MinValue, Byte.MaxValue); + if (in_checked_context){ + if (Value < Byte.MinValue || Value > Byte.MaxValue) + throw new OverflowException (); + } return new ByteConstant ((byte) Value, Location); } if (target_type == TypeManager.sbyte_type) { - CheckRange (ec, Value, target_type, SByte.MinValue, SByte.MaxValue); + if (in_checked_context){ + if (Value < SByte.MinValue || Value > SByte.MaxValue) + throw new OverflowException (); + } return new SByteConstant ((sbyte) Value, Location); } if (target_type == TypeManager.short_type) { - CheckRange (ec, Value, target_type, Int16.MinValue, Int16.MaxValue); + if (in_checked_context){ + if (Value < Int16.MinValue || Value > Int16.MaxValue) + throw new OverflowException (); + } return new ShortConstant ((short) Value, Location); } if (target_type == TypeManager.ushort_type) { - CheckRange (ec, Value, target_type, UInt16.MinValue, UInt16.MaxValue); + if (in_checked_context){ + if (Value < UInt16.MinValue || Value > UInt16.MaxValue) + throw new OverflowException (); + } return new UShortConstant ((ushort) Value, Location); } if (target_type == TypeManager.uint32_type) { - CheckRange (ec, Value, target_type, Int32.MinValue, Int32.MaxValue); + if (in_checked_context){ + if (Value < UInt32.MinValue) + throw new OverflowException (); + } return new UIntConstant ((uint) Value, Location); } if (target_type == TypeManager.int64_type) return new LongConstant ((long) Value, Location); if (target_type == TypeManager.uint64_type) { - CheckUnsigned (ec, Value, target_type); + if (in_checked_context && Value < 0) + throw new OverflowException (); return new ULongConstant ((ulong) Value, Location); } if (target_type == TypeManager.float_type) @@ -1155,7 +939,10 @@ namespace Mono.CSharp { if (target_type == TypeManager.double_type) return new DoubleConstant ((double) Value, Location); if (target_type == TypeManager.char_type) { - CheckRange (ec, Value, target_type, Char.MinValue, Char.MaxValue); + if (in_checked_context){ + if (Value < Char.MinValue || Value > Char.MaxValue) + throw new OverflowException (); + } return new CharConstant ((char) Value, Location); } if (target_type == TypeManager.decimal_type) @@ -1163,9 +950,65 @@ namespace Mono.CSharp { return null; } + + public override Constant ConvertImplicitly (Type type) + { + if (this.type == type) + return this; + + Constant c = TryImplicitIntConversion (type); + if (c != null) + return c; + + return base.ConvertImplicitly (type); + } + + /// + /// Attempts to perform an implicit constant conversion of the IntConstant + /// into a different data type using casts (See Implicit Constant + /// Expression Conversions) + /// + Constant TryImplicitIntConversion (Type target_type) + { + if (target_type == TypeManager.sbyte_type) { + if (Value >= SByte.MinValue && Value <= SByte.MaxValue) + return new SByteConstant ((sbyte) Value, loc); + } + else if (target_type == TypeManager.byte_type) { + if (Value >= Byte.MinValue && Value <= Byte.MaxValue) + return new ByteConstant ((byte) Value, loc); + } + else if (target_type == TypeManager.short_type) { + if (Value >= Int16.MinValue && Value <= Int16.MaxValue) + return new ShortConstant ((short) Value, loc); + } + else if (target_type == TypeManager.ushort_type) { + if (Value >= UInt16.MinValue && Value <= UInt16.MaxValue) + return new UShortConstant ((ushort) Value, loc); + } + else if (target_type == TypeManager.uint32_type) { + if (Value >= 0) + return new UIntConstant ((uint) Value, loc); + } + else if (target_type == TypeManager.uint64_type) { + // + // we can optimize this case: a positive int32 + // always fits on a uint64. But we need an opcode + // to do it. + // + if (Value >= 0) + return new ULongConstant ((ulong) Value, loc); + } + else if (target_type == TypeManager.double_type) + return new DoubleConstant ((double) Value, loc); + else if (target_type == TypeManager.float_type) + return new FloatConstant ((float) Value, loc); + + return null; + } } - public class UIntConstant : Constant { + public class UIntConstant : IntegralConstant { public readonly uint Value; public UIntConstant (uint v, Location loc): @@ -1191,36 +1034,6 @@ namespace Mono.CSharp { return Value; } - public override DoubleConstant ConvertToDouble () - { - return new DoubleConstant (Value, loc); - } - - public override FloatConstant ConvertToFloat () - { - return new FloatConstant (Value, loc); - } - - public override ULongConstant ConvertToULong () - { - return new ULongConstant (Value, loc); - } - - public override LongConstant ConvertToLong () - { - return new LongConstant (Value, loc); - } - - public override UIntConstant ConvertToUInt () - { - return this; - } - - public override IntConstant ConvertToInt () - { - return null; - } - public override Constant Increment () { return new UIntConstant (checked(Value + 1), loc); @@ -1242,26 +1055,41 @@ namespace Mono.CSharp { get { return Value == 0; } } - public override Constant Reduce (EmitContext ec, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, Type target_type) { if (target_type == TypeManager.byte_type) { - CheckRange (ec, Value, target_type, Char.MinValue, Char.MaxValue); + if (in_checked_context){ + if (Value < Char.MinValue || Value > Char.MaxValue) + throw new OverflowException (); + } return new ByteConstant ((byte) Value, Location); } if (target_type == TypeManager.sbyte_type) { - CheckRange (ec, Value, target_type, SByte.MinValue, SByte.MaxValue); + if (in_checked_context){ + if (Value > SByte.MaxValue) + throw new OverflowException (); + } return new SByteConstant ((sbyte) Value, Location); } if (target_type == TypeManager.short_type) { - CheckRange (ec, Value, target_type, Int16.MinValue, Int16.MaxValue); + if (in_checked_context){ + if (Value > Int16.MaxValue) + throw new OverflowException (); + } return new ShortConstant ((short) Value, Location); } if (target_type == TypeManager.ushort_type) { - CheckRange (ec, Value, target_type, UInt16.MinValue, UInt16.MaxValue); + if (in_checked_context){ + if (Value < UInt16.MinValue || Value > UInt16.MaxValue) + throw new OverflowException (); + } return new UShortConstant ((ushort) Value, Location); } if (target_type == TypeManager.int32_type) { - CheckRange (ec, Value, target_type, Int32.MinValue, Int32.MaxValue); + if (in_checked_context){ + if (Value > Int32.MaxValue) + throw new OverflowException (); + } return new IntConstant ((int) Value, Location); } if (target_type == TypeManager.int64_type) @@ -1273,7 +1101,10 @@ namespace Mono.CSharp { if (target_type == TypeManager.double_type) return new DoubleConstant ((double) Value, Location); if (target_type == TypeManager.char_type) { - CheckRange (ec, Value, target_type, Char.MinValue, Char.MaxValue); + if (in_checked_context){ + if (Value < Char.MinValue || Value > Char.MaxValue) + throw new OverflowException (); + } return new CharConstant ((char) Value, Location); } if (target_type == TypeManager.decimal_type) @@ -1284,7 +1115,7 @@ namespace Mono.CSharp { } - public class LongConstant : Constant { + public class LongConstant : IntegralConstant { public readonly long Value; public LongConstant (long v, Location loc): @@ -1297,19 +1128,17 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { - ILGenerator ig = ec.ig; - - EmitLong (ig, Value); + EmitLong (ec.ig, Value); } static public void EmitLong (ILGenerator ig, long l) { - if ((l >> 32) == 0){ + if (l >= int.MinValue && l <= int.MaxValue) { IntLiteral.EmitInt (ig, unchecked ((int) l)); - ig.Emit (OpCodes.Conv_U8); - } else { - ig.Emit (OpCodes.Ldc_I8, l); + ig.Emit (OpCodes.Conv_I8); + return; } + ig.Emit (OpCodes.Ldc_I8, l); } public override string AsString () @@ -1322,39 +1151,6 @@ namespace Mono.CSharp { return Value; } - public override DoubleConstant ConvertToDouble () - { - return new DoubleConstant (Value, loc); - } - - public override FloatConstant ConvertToFloat () - { - return new FloatConstant (Value, loc); - } - - public override ULongConstant ConvertToULong () - { - if (Value < 0) - return null; - - return new ULongConstant ((ulong) Value, loc); - } - - public override LongConstant ConvertToLong () - { - return this; - } - - public override UIntConstant ConvertToUInt () - { - return null; - } - - public override IntConstant ConvertToInt () - { - return null; - } - public override Constant Increment () { return new LongConstant (checked(Value + 1), loc); @@ -1376,34 +1172,53 @@ namespace Mono.CSharp { get { return Value == 0; } } - public override Constant Reduce (EmitContext ec, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, Type target_type) { if (target_type == TypeManager.byte_type) { - CheckRange (ec, Value, target_type, Byte.MinValue, Byte.MaxValue); + if (in_checked_context){ + if (Value < Byte.MinValue || Value > Byte.MaxValue) + throw new OverflowException (); + } return new ByteConstant ((byte) Value, Location); } if (target_type == TypeManager.sbyte_type) { - CheckRange (ec, Value, target_type, SByte.MinValue, SByte.MaxValue); + if (in_checked_context){ + if (Value < SByte.MinValue || Value > SByte.MaxValue) + throw new OverflowException (); + } return new SByteConstant ((sbyte) Value, Location); } if (target_type == TypeManager.short_type) { - CheckRange (ec, Value, target_type, Int16.MinValue, Int16.MaxValue); + if (in_checked_context){ + if (Value < Int16.MinValue || Value > Int16.MaxValue) + throw new OverflowException (); + } return new ShortConstant ((short) Value, Location); } if (target_type == TypeManager.ushort_type) { - CheckRange (ec, Value, target_type, UInt16.MinValue, UInt16.MaxValue); + if (in_checked_context){ + if (Value < UInt16.MinValue || Value > UInt16.MaxValue) + throw new OverflowException (); + } return new UShortConstant ((ushort) Value, Location); } if (target_type == TypeManager.int32_type) { - CheckRange (ec, Value, target_type, Int32.MinValue, Int32.MaxValue); + if (in_checked_context){ + if (Value < Int32.MinValue || Value > Int32.MaxValue) + throw new OverflowException (); + } return new IntConstant ((int) Value, Location); } if (target_type == TypeManager.uint32_type) { - CheckRange (ec, Value, target_type, UInt32.MinValue, UInt32.MaxValue); + if (in_checked_context){ + if (Value < UInt32.MinValue || Value > UInt32.MaxValue) + throw new OverflowException (); + } return new UIntConstant ((uint) Value, Location); } if (target_type == TypeManager.uint64_type) { - CheckUnsigned (ec, Value, target_type); + if (in_checked_context && Value < 0) + throw new OverflowException (); return new ULongConstant ((ulong) Value, Location); } if (target_type == TypeManager.float_type) @@ -1411,7 +1226,10 @@ namespace Mono.CSharp { if (target_type == TypeManager.double_type) return new DoubleConstant ((double) Value, Location); if (target_type == TypeManager.char_type) { - CheckRange (ec, Value, target_type, Char.MinValue, Char.MaxValue); + if (in_checked_context){ + if (Value < Char.MinValue || Value > Char.MaxValue) + throw new OverflowException (); + } return new CharConstant ((char) Value, Location); } if (target_type == TypeManager.decimal_type) @@ -1420,9 +1238,17 @@ namespace Mono.CSharp { return null; } + public override Constant ConvertImplicitly (Type type) + { + if (Value >= 0 && type == TypeManager.uint64_type) { + return new ULongConstant ((ulong) Value, loc); + } + + return base.ConvertImplicitly (type); + } } - public class ULongConstant : Constant { + public class ULongConstant : IntegralConstant { public readonly ulong Value; public ULongConstant (ulong v, Location loc): @@ -1450,36 +1276,6 @@ namespace Mono.CSharp { return Value; } - public override DoubleConstant ConvertToDouble () - { - return new DoubleConstant (Value, loc); - } - - public override FloatConstant ConvertToFloat () - { - return new FloatConstant (Value, loc); - } - - public override ULongConstant ConvertToULong () - { - return this; - } - - public override LongConstant ConvertToLong () - { - return null; - } - - public override UIntConstant ConvertToUInt () - { - return null; - } - - public override IntConstant ConvertToInt () - { - return null; - } - public override Constant Increment () { return new ULongConstant (checked(Value + 1), loc); @@ -1501,34 +1297,41 @@ namespace Mono.CSharp { get { return Value == 0; } } - public override Constant Reduce (EmitContext ec, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, Type target_type) { if (target_type == TypeManager.byte_type) { - CheckRange (ec, Value, target_type, Byte.MaxValue); + if (in_checked_context && Value > Byte.MaxValue) + throw new OverflowException (); return new ByteConstant ((byte) Value, Location); } if (target_type == TypeManager.sbyte_type) { - CheckRange (ec, Value, target_type, (ulong) SByte.MaxValue); + if (in_checked_context && Value > ((ulong) SByte.MaxValue)) + throw new OverflowException (); return new SByteConstant ((sbyte) Value, Location); } if (target_type == TypeManager.short_type) { - CheckRange (ec, Value, target_type, (ulong) Int16.MaxValue); + if (in_checked_context && Value > ((ulong) Int16.MaxValue)) + throw new OverflowException (); return new ShortConstant ((short) Value, Location); } if (target_type == TypeManager.ushort_type) { - CheckRange (ec, Value, target_type, UInt16.MaxValue); + if (in_checked_context && Value > UInt16.MaxValue) + throw new OverflowException (); return new UShortConstant ((ushort) Value, Location); } if (target_type == TypeManager.int32_type) { - CheckRange (ec, Value, target_type, Int32.MaxValue); + if (in_checked_context && Value > UInt32.MaxValue) + throw new OverflowException (); return new IntConstant ((int) Value, Location); } if (target_type == TypeManager.uint32_type) { - CheckRange (ec, Value, target_type, UInt32.MaxValue); + if (in_checked_context && Value > UInt32.MaxValue) + throw new OverflowException (); return new UIntConstant ((uint) Value, Location); } if (target_type == TypeManager.int64_type) { - CheckRange (ec, Value, target_type, (ulong) Int64.MaxValue); + if (in_checked_context && Value > Int64.MaxValue) + throw new OverflowException (); return new LongConstant ((long) Value, Location); } if (target_type == TypeManager.float_type) @@ -1536,7 +1339,8 @@ namespace Mono.CSharp { if (target_type == TypeManager.double_type) return new DoubleConstant ((double) Value, Location); if (target_type == TypeManager.char_type) { - CheckRange (ec, Value, target_type, Char.MaxValue); + if (in_checked_context && Value > Char.MaxValue) + throw new OverflowException (); return new CharConstant ((char) Value, Location); } if (target_type == TypeManager.decimal_type) @@ -1548,7 +1352,7 @@ namespace Mono.CSharp { } public class FloatConstant : Constant { - public readonly float Value; + public float Value; public FloatConstant (float v, Location loc): base (loc) @@ -1573,31 +1377,6 @@ namespace Mono.CSharp { return Value; } - public override DoubleConstant ConvertToDouble () - { - return new DoubleConstant (Value, loc); - } - - public override FloatConstant ConvertToFloat () - { - return this; - } - - public override LongConstant ConvertToLong () - { - return null; - } - - public override UIntConstant ConvertToUInt () - { - return null; - } - - public override IntConstant ConvertToInt () - { - return null; - } - public override Constant Increment () { return new FloatConstant (checked(Value + 1), loc); @@ -1615,28 +1394,73 @@ namespace Mono.CSharp { } } - public override Constant Reduce (EmitContext ec, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, Type target_type) { - if (target_type == TypeManager.byte_type) + if (target_type == TypeManager.byte_type) { + if (in_checked_context){ + if (Value < byte.MinValue || Value > byte.MaxValue) + throw new OverflowException (); + } return new ByteConstant ((byte) Value, Location); - if (target_type == TypeManager.sbyte_type) + } + if (target_type == TypeManager.sbyte_type) { + if (in_checked_context){ + if (Value < sbyte.MinValue || Value > sbyte.MaxValue) + throw new OverflowException (); + } return new SByteConstant ((sbyte) Value, Location); - if (target_type == TypeManager.short_type) + } + if (target_type == TypeManager.short_type) { + if (in_checked_context){ + if (Value < short.MinValue || Value > short.MaxValue) + throw new OverflowException (); + } return new ShortConstant ((short) Value, Location); - if (target_type == TypeManager.ushort_type) + } + if (target_type == TypeManager.ushort_type) { + if (in_checked_context){ + if (Value < ushort.MinValue || Value > ushort.MaxValue) + throw new OverflowException (); + } return new UShortConstant ((ushort) Value, Location); - if (target_type == TypeManager.int32_type) + } + if (target_type == TypeManager.int32_type) { + if (in_checked_context){ + if (Value < int.MinValue || Value > int.MaxValue) + throw new OverflowException (); + } return new IntConstant ((int) Value, Location); - if (target_type == TypeManager.uint32_type) + } + if (target_type == TypeManager.uint32_type) { + if (in_checked_context){ + if (Value < uint.MinValue || Value > uint.MaxValue) + throw new OverflowException (); + } return new UIntConstant ((uint) Value, Location); - if (target_type == TypeManager.int64_type) + } + if (target_type == TypeManager.int64_type) { + if (in_checked_context){ + if (Value < long.MinValue || Value > long.MaxValue) + throw new OverflowException (); + } return new LongConstant ((long) Value, Location); - if (target_type == TypeManager.uint64_type) + } + if (target_type == TypeManager.uint64_type) { + if (in_checked_context){ + if (Value < ulong.MinValue || Value > ulong.MaxValue) + throw new OverflowException (); + } return new ULongConstant ((ulong) Value, Location); + } if (target_type == TypeManager.double_type) return new DoubleConstant ((double) Value, Location); - if (target_type == TypeManager.char_type) + if (target_type == TypeManager.char_type) { + if (in_checked_context){ + if (Value < (float) char.MinValue || Value > (float) char.MaxValue) + throw new OverflowException (); + } return new CharConstant ((char) Value, Location); + } if (target_type == TypeManager.decimal_type) return new DecimalConstant ((decimal) Value, Location); @@ -1646,7 +1470,7 @@ namespace Mono.CSharp { } public class DoubleConstant : Constant { - public readonly double Value; + public double Value; public DoubleConstant (double v, Location loc): base (loc) @@ -1671,36 +1495,6 @@ namespace Mono.CSharp { return Value; } - public override DoubleConstant ConvertToDouble () - { - return this; - } - - public override FloatConstant ConvertToFloat () - { - return null; - } - - public override ULongConstant ConvertToULong () - { - return null; - } - - public override LongConstant ConvertToLong () - { - return null; - } - - public override UIntConstant ConvertToUInt () - { - return null; - } - - public override IntConstant ConvertToInt () - { - return null; - } - public override Constant Increment () { return new DoubleConstant (checked(Value + 1), loc); @@ -1718,32 +1512,71 @@ namespace Mono.CSharp { } } - public override Constant Reduce (EmitContext ec, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, Type target_type) { if (target_type == TypeManager.byte_type) { - CheckRange (ec, Value, target_type, Byte.MinValue, Byte.MaxValue); + if (in_checked_context){ + if (Value < Byte.MinValue || Value > Byte.MaxValue) + throw new OverflowException (); + } return new ByteConstant ((byte) Value, Location); } if (target_type == TypeManager.sbyte_type) { - CheckRange (ec, Value, target_type, SByte.MinValue, SByte.MaxValue); + if (in_checked_context){ + if (Value < SByte.MinValue || Value > SByte.MaxValue) + throw new OverflowException (); + } return new SByteConstant ((sbyte) Value, Location); } - if (target_type == TypeManager.short_type) + if (target_type == TypeManager.short_type) { + if (in_checked_context){ + if (Value < short.MinValue || Value > short.MaxValue) + throw new OverflowException (); + } return new ShortConstant ((short) Value, Location); - if (target_type == TypeManager.ushort_type) + } + if (target_type == TypeManager.ushort_type) { + if (in_checked_context){ + if (Value < ushort.MinValue || Value > ushort.MaxValue) + throw new OverflowException (); + } return new UShortConstant ((ushort) Value, Location); - if (target_type == TypeManager.int32_type) + } + if (target_type == TypeManager.int32_type) { + if (in_checked_context){ + if (Value < int.MinValue || Value > int.MaxValue) + throw new OverflowException (); + } return new IntConstant ((int) Value, Location); - if (target_type == TypeManager.uint32_type) + } + if (target_type == TypeManager.uint32_type) { + if (in_checked_context){ + if (Value < uint.MinValue || Value > uint.MaxValue) + throw new OverflowException (); + } return new UIntConstant ((uint) Value, Location); - if (target_type == TypeManager.int64_type) + } + if (target_type == TypeManager.int64_type) { + if (in_checked_context){ + if (Value < long.MinValue || Value > long.MaxValue) + throw new OverflowException (); + } return new LongConstant ((long) Value, Location); - if (target_type == TypeManager.uint64_type) + } + if (target_type == TypeManager.uint64_type) { + if (in_checked_context){ + if (Value < ulong.MinValue || Value > ulong.MaxValue) + throw new OverflowException (); + } return new ULongConstant ((ulong) Value, Location); + } if (target_type == TypeManager.float_type) return new FloatConstant ((float) Value, Location); if (target_type == TypeManager.char_type) { - CheckRange (ec, Value, target_type, char.MinValue, char.MaxValue); + if (in_checked_context){ + if (Value < (double) char.MinValue || Value > (double) char.MaxValue) + throw new OverflowException (); + } return new CharConstant ((char) Value, Location); } if (target_type == TypeManager.decimal_type) @@ -1825,7 +1658,7 @@ namespace Mono.CSharp { } } - public override Constant Reduce (EmitContext ec, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, Type target_type) { if (target_type == TypeManager.sbyte_type) return new SByteConstant ((sbyte)Value, loc); @@ -1902,7 +1735,7 @@ namespace Mono.CSharp { } } - public override Constant Reduce (EmitContext ec, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, Type target_type) { return null; }