+ public virtual Constant ToType (Type type, Location loc)
+ {
+ if (Type == type)
+ return this;
+
+ if (type == TypeManager.object_type)
+ return this;
+
+ if (!Convert.ImplicitStandardConversionExists (Convert.ConstantEC, this, type)){
+ Error_ValueCannotBeConverted (loc, type, false);
+ 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 ();
+ }
+
+ public abstract Constant Reduce (EmitContext ec, Type target_type);
+
+ /// <summary>
+ /// Attempts to do a compile-time folding of a constant cast.
+ /// </summary>
+ public Constant TryReduce (EmitContext ec, Type target_type, Location loc)
+ {
+ try {
+ 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)",
+ this.GetValue (), TypeManager.CSharpName (target_type));
+ }
+ return null;
+ }
+ }
+
+ Constant TryReduce (EmitContext ec, Type target_type)
+ {
+ if (Type == target_type)
+ return this;
+
+ if (TypeManager.IsEnumType (target_type)) {
+ Constant c = TryReduce (ec, TypeManager.EnumToUnderlying (target_type));
+ if (c == null)
+ return null;
+
+ return new EnumConstant (c, target_type);
+ }
+
+ return Reduce (ec, target_type);
+ }
+
+