// Miguel de Icaza (miguel@ximian.com)
// Marek Safar (marek.safar@seznam.cz)
//
-// (C) 2001 Ximian, Inc.
-//
+// Copyright 2001-2003 Ximian, Inc.
+// Copyright 2003-2008 Novell, Inc.
//
namespace Mono.CSharp {
using System;
using System.Reflection.Emit;
+ using System.Collections;
/// <summary>
/// Base class for constants and literals.
return this.GetType ().Name + " (" + AsString () + ")";
}
- public override bool GetAttributableValue (Type value_type, out object value)
+ public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
{
if (value_type == TypeManager.object_type) {
value = GetTypedValue ();
return true;
}
- Constant c = ImplicitConversionRequired (value_type, loc);
+ Constant c = ImplicitConversionRequired (ec, value_type, loc);
if (c == null) {
value = null;
return false;
return this;
}
- public Constant ImplicitConversionRequired (Type type, Location loc)
+ public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
+ {
+ if (!expl && IsLiteral &&
+ (TypeManager.IsPrimitiveType (target) || type == TypeManager.decimal_type) &&
+ (TypeManager.IsPrimitiveType (type) || type == TypeManager.decimal_type)) {
+ Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
+ AsString (), TypeManager.CSharpName (target));
+ } else {
+ base.Error_ValueCannotBeConverted (ec, loc, target, expl);
+ }
+ }
+
+ public Constant ImplicitConversionRequired (EmitContext ec, Type type, Location loc)
{
Constant c = ConvertImplicitly (type);
if (c == null)
- Error_ValueCannotBeConverted (null, loc, type, false);
+ Error_ValueCannotBeConverted (ec, loc, type, false);
return c;
}
// 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));
+ throw new InternalErrorException ("Missing constant conversion between `{0}' and `{1}'",
+ TypeManager.CSharpName (Type), TypeManager.CSharpName (type));
}
return CreateConstant (type, constant_value, 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);
+ Type real_type = TypeManager.GetEnumUnderlyingType (t);
return new EnumConstant (CreateConstant (real_type, v, loc), t);
}
if (v == null && !TypeManager.IsValueType (t))
- return new EmptyConstantCast (new NullConstant (loc), t);
+ return new EmptyConstantCast (new NullLiteral (loc), t);
throw new Exception ("Unknown type for constant (" + t +
"), details: " + v);
}
+
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ ArrayList args = new ArrayList (2);
+ args.Add (new Argument (this));
+ args.Add (new Argument (
+ new TypeOf (new TypeExpression (type, loc), loc)));
+
+ return CreateExpressionFactoryCall ("Constant", args);
+ }
+
+
/// <summary>
/// Maybe ConvertTo name is better. It tries to convert `this' constant to target_type.
/// It throws OverflowException
return TryReduce (ec, target_type);
}
catch (OverflowException) {
- 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;
+ 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));
+ } else {
+ Error_ValueCannotBeConverted (ec, loc, target_type, false);
+ }
+
+ return New.Constantify (target_type);
}
}
return this;
if (TypeManager.IsEnumType (target_type)) {
- Constant c = TryReduce (ec, TypeManager.EnumToUnderlying (target_type));
+ Constant c = TryReduce (ec, TypeManager.GetEnumUnderlyingType (target_type));
if (c == null)
return null;
get;
}
+ //
+ // When constant is declared as literal
+ //
+ public virtual bool IsLiteral {
+ get { return false; }
+ }
+
//
// Returns true iff 1) the stack type of this is one of Object,
// int32, int64 and 2) this == 0 or this == null.
get { return false; }
}
+ public override void EmitSideEffect (EmitContext ec)
+ {
+ // do nothing
+ }
+
protected override void CloneTo (CloneContext clonectx, Expression target)
{
// CloneTo: Nothing, we do not keep any state on this expression
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ // A constant cannot be of generic type
+ }
}
public abstract class IntegralConstant : Constant {
ig.Emit (OpCodes.Conv_I8);
return;
}
+
+ if (l >= 0 && l <= uint.MaxValue) {
+ IntLiteral.EmitInt (ig, unchecked ((int) l));
+ ig.Emit (OpCodes.Conv_U8);
+ return;
+ }
+
ig.Emit (OpCodes.Ldc_I8, l);
}
{
if (target_type == TypeManager.byte_type) {
if (in_checked_context){
- if (Value < byte.MinValue || Value > byte.MaxValue)
+ if (Value < byte.MinValue || Value > byte.MaxValue || float.IsNaN (Value))
throw new OverflowException ();
}
return new ByteConstant ((byte) Value, Location);
}
if (target_type == TypeManager.sbyte_type) {
if (in_checked_context){
- if (Value < sbyte.MinValue || Value > sbyte.MaxValue)
+ if (Value < sbyte.MinValue || Value > sbyte.MaxValue || float.IsNaN (Value))
throw new OverflowException ();
}
return new SByteConstant ((sbyte) Value, Location);
}
if (target_type == TypeManager.short_type) {
if (in_checked_context){
- if (Value < short.MinValue || Value > short.MaxValue)
+ if (Value < short.MinValue || Value > short.MaxValue || float.IsNaN (Value))
throw new OverflowException ();
}
return new ShortConstant ((short) Value, Location);
}
if (target_type == TypeManager.ushort_type) {
if (in_checked_context){
- if (Value < ushort.MinValue || Value > ushort.MaxValue)
+ if (Value < ushort.MinValue || Value > ushort.MaxValue || float.IsNaN (Value))
throw new OverflowException ();
}
return new UShortConstant ((ushort) Value, Location);
}
if (target_type == TypeManager.int32_type) {
if (in_checked_context){
- if (Value < int.MinValue || Value > int.MaxValue)
+ if (Value < int.MinValue || Value > int.MaxValue || float.IsNaN (Value))
throw new OverflowException ();
}
return new IntConstant ((int) Value, Location);
}
if (target_type == TypeManager.uint32_type) {
if (in_checked_context){
- if (Value < uint.MinValue || Value > uint.MaxValue)
+ if (Value < uint.MinValue || Value > uint.MaxValue || float.IsNaN (Value))
throw new OverflowException ();
}
return new UIntConstant ((uint) Value, Location);
}
if (target_type == TypeManager.int64_type) {
if (in_checked_context){
- if (Value < long.MinValue || Value > long.MaxValue)
+ if (Value < long.MinValue || Value > long.MaxValue || float.IsNaN (Value))
throw new OverflowException ();
}
return new LongConstant ((long) Value, Location);
}
if (target_type == TypeManager.uint64_type) {
if (in_checked_context){
- if (Value < ulong.MinValue || Value > ulong.MaxValue)
+ if (Value < ulong.MinValue || Value > ulong.MaxValue || float.IsNaN (Value))
throw new OverflowException ();
}
return new ULongConstant ((ulong) Value, Location);
return new DoubleConstant ((double) Value, Location);
if (target_type == TypeManager.char_type) {
if (in_checked_context){
- if (Value < (float) char.MinValue || Value > (float) char.MaxValue)
+ if (Value < (float) char.MinValue || Value > (float) char.MaxValue || float.IsNaN (Value))
throw new OverflowException ();
}
return new CharConstant ((char) Value, Location);
{
if (target_type == TypeManager.byte_type) {
if (in_checked_context){
- if (Value < Byte.MinValue || Value > Byte.MaxValue)
+ if (Value < Byte.MinValue || Value > Byte.MaxValue || double.IsNaN (Value))
throw new OverflowException ();
}
return new ByteConstant ((byte) Value, Location);
}
if (target_type == TypeManager.sbyte_type) {
if (in_checked_context){
- if (Value < SByte.MinValue || Value > SByte.MaxValue)
+ if (Value < SByte.MinValue || Value > SByte.MaxValue || double.IsNaN (Value))
throw new OverflowException ();
}
return new SByteConstant ((sbyte) Value, Location);
}
if (target_type == TypeManager.short_type) {
if (in_checked_context){
- if (Value < short.MinValue || Value > short.MaxValue)
+ if (Value < short.MinValue || Value > short.MaxValue || double.IsNaN (Value))
throw new OverflowException ();
}
return new ShortConstant ((short) Value, Location);
}
if (target_type == TypeManager.ushort_type) {
if (in_checked_context){
- if (Value < ushort.MinValue || Value > ushort.MaxValue)
+ if (Value < ushort.MinValue || Value > ushort.MaxValue || double.IsNaN (Value))
throw new OverflowException ();
}
return new UShortConstant ((ushort) Value, Location);
}
if (target_type == TypeManager.int32_type) {
if (in_checked_context){
- if (Value < int.MinValue || Value > int.MaxValue)
+ if (Value < int.MinValue || Value > int.MaxValue || double.IsNaN (Value))
throw new OverflowException ();
}
return new IntConstant ((int) Value, Location);
}
if (target_type == TypeManager.uint32_type) {
if (in_checked_context){
- if (Value < uint.MinValue || Value > uint.MaxValue)
+ if (Value < uint.MinValue || Value > uint.MaxValue || double.IsNaN (Value))
throw new OverflowException ();
}
return new UIntConstant ((uint) Value, Location);
}
if (target_type == TypeManager.int64_type) {
if (in_checked_context){
- if (Value < long.MinValue || Value > long.MaxValue)
+ if (Value < long.MinValue || Value > long.MaxValue || double.IsNaN (Value))
throw new OverflowException ();
}
return new LongConstant ((long) Value, Location);
}
if (target_type == TypeManager.uint64_type) {
if (in_checked_context){
- if (Value < ulong.MinValue || Value > ulong.MaxValue)
+ if (Value < ulong.MinValue || Value > ulong.MaxValue || double.IsNaN (Value))
throw new OverflowException ();
}
return new ULongConstant ((ulong) Value, Location);
return new FloatConstant ((float) Value, Location);
if (target_type == TypeManager.char_type) {
if (in_checked_context){
- if (Value < (double) char.MinValue || Value > (double) char.MaxValue)
+ if (Value < (double) char.MinValue || Value > (double) char.MaxValue || double.IsNaN (Value))
throw new OverflowException ();
}
return new CharConstant ((char) Value, Location);
override public string AsString ()
{
- return Value.ToString ();
+ return Value.ToString () + "M";
}
public override object GetValue ()
if (power == 0 && Value <= int.MaxValue && Value >= int.MinValue)
{
+ if (TypeManager.void_decimal_ctor_int_arg == null) {
+ TypeManager.void_decimal_ctor_int_arg = TypeManager.GetPredefinedConstructor (
+ TypeManager.decimal_type, loc, TypeManager.int32_type);
+
+ if (TypeManager.void_decimal_ctor_int_arg == null)
+ return;
+ }
+
IntConstant.EmitInt (ig, (int)Value);
ig.Emit (OpCodes.Newobj, TypeManager.void_decimal_ctor_int_arg);
return;
// power
IntConstant.EmitInt (ig, power);
+ if (TypeManager.void_decimal_ctor_five_args == null) {
+ TypeManager.void_decimal_ctor_five_args = TypeManager.GetPredefinedConstructor (
+ TypeManager.decimal_type, loc, TypeManager.int32_type, TypeManager.int32_type,
+ TypeManager.int32_type, TypeManager.bool_type, TypeManager.byte_type);
+
+ if (TypeManager.void_decimal_ctor_five_args == null)
+ return;
+ }
+
ig.Emit (OpCodes.Newobj, TypeManager.void_decimal_ctor_five_args);
}
public override void Emit (EmitContext ec)
{
- if (Value == null)
+ if (Value == null) {
ec.ig.Emit (OpCodes.Ldnull);
- else
- ec.ig.Emit (OpCodes.Ldstr, Value);
+ return;
+ }
+
+ //
+ // Use string.Empty for both literals and constants even if
+ // it's not allowed at language level
+ //
+ if (Value.Length == 0 && RootContext.Optimize && ec.TypeContainer.TypeBuilder != TypeManager.string_type) {
+ if (TypeManager.string_empty == null)
+ TypeManager.string_empty = TypeManager.GetPredefinedField (TypeManager.string_type, "Empty", loc);
+
+ if (TypeManager.string_empty != null) {
+ ec.ig.Emit (OpCodes.Ldsfld, TypeManager.string_empty);
+ return;
+ }
+ }
+
+ ec.ig.Emit (OpCodes.Ldstr, Value);
}
public override Constant Increment ()
}
}
-}
+ /// <summary>
+ /// The value is constant, but when emitted has a side effect. This is
+ /// used by BitwiseAnd to ensure that the second expression is invoked
+ /// regardless of the value of the left side.
+ /// </summary>
+
+ public class SideEffectConstant : Constant {
+ public Constant value;
+ Expression side_effect;
+
+ public SideEffectConstant (Constant value, Expression side_effect, Location loc) : base (loc)
+ {
+ this.value = value;
+ while (side_effect is SideEffectConstant)
+ side_effect = ((SideEffectConstant) side_effect).side_effect;
+ this.side_effect = side_effect;
+ eclass = ExprClass.Value;
+ type = value.Type;
+ }
+
+ public override string AsString ()
+ {
+ return value.AsString ();
+ }
+
+ public override object GetValue ()
+ {
+ return value.GetValue ();
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ side_effect.EmitSideEffect (ec);
+ value.Emit (ec);
+ }
+
+ public override void EmitSideEffect (EmitContext ec)
+ {
+ side_effect.EmitSideEffect (ec);
+ value.EmitSideEffect (ec);
+ }
+ public override bool IsDefaultValue {
+ get { return value.IsDefaultValue; }
+ }
+ public override Constant Increment ()
+ {
+ throw new NotSupportedException ();
+ }
+
+ public override bool IsNegative {
+ get { return value.IsNegative; }
+ }
+
+ public override bool IsZeroInteger {
+ get { return value.IsZeroInteger; }
+ }
+
+ public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
+ {
+ Constant new_value = value.ConvertExplicitly (in_checked_context, target_type);
+ return new_value == null ? null : new SideEffectConstant (new_value, side_effect, new_value.Location);
+ }
+ }
+}