X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fconstant.cs;h=c04ad0246df1417ee4d111d3245a9f5e4e2370c1;hb=7674f7142c1f8e30c32d8559d56f3bfc91387ea0;hp=cc3f6983805a06b04ef977cfb50b102dfc74495a;hpb=b39d5edf62fb3908e10647e1a7e60dadeb88b2be;p=mono.git diff --git a/mcs/mcs/constant.cs b/mcs/mcs/constant.cs index cc3f6983805..c04ad0246df 100644 --- a/mcs/mcs/constant.cs +++ b/mcs/mcs/constant.cs @@ -5,14 +5,14 @@ // 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; - using System.Reflection.Emit; +namespace Mono.CSharp { /// /// Base class for constants and literals. @@ -39,18 +39,6 @@ namespace Mono.CSharp { return this.GetType ().Name + " (" + AsString () + ")"; } - public override bool GetAttributableValue (Type valueType, out object value) - { - Constant c = ToType (valueType, 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. @@ -62,289 +50,171 @@ namespace Mono.CSharp { return GetValue (); } - /// - /// Constants are always born in a fully resolved state - /// - public override Expression DoResolve (EmitContext ec) - { - 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) + public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl) { - 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) - { - IntConstant c = ConvertToInt (); - - if (c == null) - Error_ValueCannotBeConverted (loc, TypeManager.int32_type, false); - - return c; + if (!expl && IsLiteral && + (TypeManager.IsPrimitiveType (target) || type == TypeManager.decimal_type) && + (TypeManager.IsPrimitiveType (type) || type == TypeManager.decimal_type)) { + ec.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 DecimalConstant ToDecimal (Location loc) + public Constant ImplicitConversionRequired (ResolveContext ec, TypeSpec type, Location loc) { - DecimalConstant c = ConvertToDecimal (); - + Constant c = ConvertImplicitly (ec, type); if (c == null) - Error_ValueCannotBeConverted (loc, TypeManager.decimal_type, false); + Error_ValueCannotBeConverted (ec, loc, type, false); return c; } - public virtual Constant ToType (Type type, Location loc) + public virtual Constant ConvertImplicitly (ResolveContext rc, TypeSpec type) { - if (Type == type) - return this; - - if (type == TypeManager.object_type) + if (this.type == type) return this; - if (!Convert.ImplicitStandardConversionExists (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 static void CheckRange (bool inCheckedContext, ulong value, ulong max) - { - if (!inCheckedContext) - return; + throw new InternalErrorException ("Missing constant conversion between `{0}' and `{1}'", + TypeManager.CSharpName (Type), TypeManager.CSharpName (type)); + } - if (value > max) - throw new OverflowException (); + return CreateConstant (rc, type, constant_value, loc); } - protected static void CheckRange (bool inCheckedContext, double value, long min, long max) + // + // Returns a constant instance based on Type + // + public static Constant CreateConstant (ResolveContext rc, TypeSpec t, object v, Location loc) { - if (!inCheckedContext) - return; - - if (((value < min) || (value > max))) - throw new OverflowException (); - - if (double.IsNaN (value)) - throw new OverflowException (); + return CreateConstantFromValue (t, v, loc).Resolve (rc); } - protected static void CheckRange (bool inCheckedContext, double value, ulong min, ulong max) + public static Constant CreateConstantFromValue (TypeSpec t, object v, Location loc) { - if (!inCheckedContext) - return; + 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)) { + var real_type = EnumSpec.GetUnderlyingType (t); + return new EnumConstant (CreateConstantFromValue (real_type, v, loc).Resolve (null), t); + } + if (v == null) { + if (TypeManager.IsNullableType (t)) + return Nullable.LiftedNull.Create (t, loc); - if (((value < min) || (value > max))) - throw new OverflowException (); + if (TypeManager.IsReferenceType (t)) + return new NullConstant (t, loc); + } - if (double.IsNaN (value)) - throw new OverflowException (); + throw new InternalErrorException ("Constant value `{0}' has unexpected underlying type `{1}'", + v, TypeManager.CSharpName (t)); } - protected static void CheckUnsigned (bool inCheckedContext, long value) + public override Expression CreateExpressionTree (ResolveContext ec) { - if (!inCheckedContext) - return; + Arguments args = new Arguments (2); + args.Add (new Argument (this)); + args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc))); - if (value < 0) - throw new OverflowException (); + return CreateExpressionFactoryCall (ec, "Constant", args); } + /// /// Maybe ConvertTo name is better. It tries to convert `this' constant to target_type. /// It throws OverflowException /// - public abstract Constant Reduce (bool inCheckedContext, Type target_type); + // DON'T CALL THIS METHOD DIRECTLY AS IT DOES NOT HANDLE ENUMS + public abstract Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type); /// /// Attempts to do a compile-time folding of a constant cast. /// - public Constant TryReduce (EmitContext ec, Type target_type, Location loc) + public Constant TryReduce (ResolveContext ec, TypeSpec target_type, Location loc) { try { - return TryReduce (ec, target_type); + 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)); - throw; + if (ec.ConstantCheckState) { + ec.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).Resolve (ec); } } - Constant TryReduce (EmitContext ec, Type target_type) + Constant TryReduce (ResolveContext ec, TypeSpec target_type) { if (Type == target_type) return this; + Constant c; if (TypeManager.IsEnumType (target_type)) { - Constant c = TryReduce (ec, TypeManager.EnumToUnderlying (target_type)); + c = TryReduce (ec, EnumSpec.GetUnderlyingType (target_type)); if (c == null) return null; - return new EnumConstant (c, target_type); + return new EnumConstant (c, target_type).Resolve (ec); } - return Reduce (ec.ConstantCheckState, target_type); - } - - - public virtual DecimalConstant ConvertToDecimal () - { - return null; - } - - public virtual DoubleConstant ConvertToDouble () - { - return null; - } - - public virtual FloatConstant ConvertToFloat () - { - return null; - } - - public virtual ULongConstant ConvertToULong () - { - return null; - } - - public virtual LongConstant ConvertToLong () - { - return null; - } - - public virtual UIntConstant ConvertToUInt () - { - return null; - } + c = ConvertExplicitly (ec.ConstantCheckState, target_type); + if (c != null) + c = c.Resolve (ec); - public virtual IntConstant ConvertToInt () - { - return null; + return c; } - public abstract Constant Increment (); - /// /// Need to pass type as the constant can require a boxing /// and in such case no optimization is possible /// - public bool IsDefaultInitializer (Type type) + public bool IsDefaultInitializer (TypeSpec type) { if (type == Type) return IsDefaultValue; - return Type == TypeManager.null_type; + return this is NullLiteral; } public abstract bool IsDefaultValue { @@ -355,6 +225,17 @@ namespace Mono.CSharp { get; } + // + // When constant is declared as literal + // + public virtual bool IsLiteral { + get { return false; } + } + + public virtual bool IsOneInteger { + 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. @@ -362,6 +243,42 @@ namespace Mono.CSharp { public virtual bool IsZeroInteger { 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 System.Linq.Expressions.Expression MakeExpression (BuilderContext ctx) + { + return System.Linq.Expressions.Expression.Constant (GetTypedValue (), type.GetMetaInfo ()); + } + + public new Constant Resolve (ResolveContext rc) + { + if (eclass != ExprClass.Unresolved) + return this; + + // Resolved constant has to be still a constant + Constant c = (Constant) DoResolve (rc); + if (c == null) + return null; + + if ((c.eclass & ExprClass.Value) == 0) { + c.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc); + return null; + } + + if (c.type == null) + throw new InternalErrorException ("Expression `{0}' did not set its type after Resolve", c.GetType ()); + + return c; + } } public abstract class IntegralConstant : Constant { @@ -370,18 +287,20 @@ namespace Mono.CSharp { { } - public override void Error_ValueCannotBeConverted (Location loc, Type target, bool expl) + public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl) { try { - Reduce (true, target); - base.Error_ValueCannotBeConverted (loc, target, expl); + ConvertExplicitly (true, target); + base.Error_ValueCannotBeConverted (ec, loc, target, expl); } - catch + catch { - Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'", + ec.Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'", GetValue ().ToString (), TypeManager.CSharpName (target)); } } + + public abstract Constant Increment (); } public class BoolConstant : Constant { @@ -390,9 +309,6 @@ namespace Mono.CSharp { public BoolConstant (bool val, Location loc): base (loc) { - type = TypeManager.bool_type; - eclass = ExprClass.Value; - Value = val; } @@ -401,25 +317,31 @@ namespace Mono.CSharp { return Value ? "true" : "false"; } + protected override Expression DoResolve (ResolveContext ec) + { + type = TypeManager.bool_type; + eclass = ExprClass.Value; + return this; + } + public override object GetValue () { return (object) Value; } - + + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) + { + enc.Stream.Write (Value); + } public override void Emit (EmitContext ec) { if (Value) - ec.ig.Emit (OpCodes.Ldc_I4_1); + ec.Emit (OpCodes.Ldc_I4_1); else - ec.ig.Emit (OpCodes.Ldc_I4_0); + ec.Emit (OpCodes.Ldc_I4_0); } - public override Constant Increment () - { - throw new NotSupportedException (); - } - public override bool IsDefaultValue { get { return !Value; @@ -436,7 +358,7 @@ namespace Mono.CSharp { get { return Value == false; } } - public override Constant Reduce (bool inCheckedContext, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) { return null; } @@ -449,54 +371,34 @@ namespace Mono.CSharp { public ByteConstant (byte v, Location loc): base (loc) { - type = TypeManager.byte_type; - eclass = ExprClass.Value; Value = v; } - public override void Emit (EmitContext ec) - { - IntLiteral.EmitInt (ec.ig, Value); - } - - public override string AsString () - { - return Value.ToString (); - } - - public override object GetValue () - { - return Value; - } - - public override DoubleConstant ConvertToDouble () - { - return new DoubleConstant (Value, loc); - } - - public override FloatConstant ConvertToFloat () + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) { - return new FloatConstant (Value, loc); + enc.Stream.Write (Value); } - public override ULongConstant ConvertToULong () + public override void Emit (EmitContext ec) { - return new ULongConstant (Value, loc); + ec.EmitInt (Value); } - public override LongConstant ConvertToLong () + public override string AsString () { - return new LongConstant (Value, loc); + return Value.ToString (); } - public override UIntConstant ConvertToUInt () + protected override Expression DoResolve (ResolveContext ec) { - return new UIntConstant (Value, loc); + type = TypeManager.byte_type; + eclass = ExprClass.Value; + return this; } - public override IntConstant ConvertToInt () + public override object GetValue () { - return new IntConstant (Value, loc); + return Value; } public override Constant Increment () @@ -510,6 +412,12 @@ namespace Mono.CSharp { } } + public override bool IsOneInteger { + get { + return Value == 1; + } + } + public override bool IsNegative { get { return false; @@ -520,10 +428,13 @@ namespace Mono.CSharp { get { return Value == 0; } } - public override Constant Reduce (bool inCheckedContext, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) { if (target_type == TypeManager.sbyte_type) { - CheckRange (inCheckedContext, Value, 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) @@ -557,18 +468,28 @@ namespace Mono.CSharp { public CharConstant (char v, Location loc): base (loc) + { + Value = v; + } + + protected override Expression DoResolve (ResolveContext rc) { type = TypeManager.char_type; eclass = ExprClass.Value; - Value = v; + return this; + } + + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) + { + enc.Stream.Write ((ushort) Value); } public override void Emit (EmitContext ec) { - IntLiteral.EmitInt (ec.ig, Value); + ec.EmitInt (Value); } - static public string descape (char c) + static string descape (char c) { switch (c){ case '\a': @@ -607,41 +528,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); - } - public override bool IsDefaultValue { get { return Value == 0; @@ -658,18 +544,27 @@ namespace Mono.CSharp { get { return Value == '\0'; } } - public override Constant Reduce (bool inCheckedContext, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) { if (target_type == TypeManager.byte_type) { - CheckRange (inCheckedContext, Value, 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 (inCheckedContext, Value, 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 (inCheckedContext, Value, 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) @@ -698,57 +593,34 @@ namespace Mono.CSharp { public SByteConstant (sbyte v, Location loc): base (loc) { - type = TypeManager.sbyte_type; - eclass = ExprClass.Value; Value = v; } - public override void Emit (EmitContext ec) - { - IntLiteral.EmitInt (ec.ig, Value); - } - - public override string AsString () - { - return Value.ToString (); - } - - public override object GetValue () - { - return Value; - } - - public override DoubleConstant ConvertToDouble () - { - return new DoubleConstant (Value, loc); - } - - public override FloatConstant ConvertToFloat () + protected override Expression DoResolve (ResolveContext rc) { - return new FloatConstant (Value, loc); + type = TypeManager.sbyte_type; + eclass = ExprClass.Value; + return this; } - public override ULongConstant ConvertToULong () + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) { - if (Value >= 0) - return new ULongConstant ((ulong) Value, loc); - - return null; + enc.Stream.Write (Value); } - public override LongConstant ConvertToLong () + public override void Emit (EmitContext ec) { - return new LongConstant (Value, loc); + ec.EmitInt (Value); } - public override UIntConstant ConvertToUInt () + public override string AsString () { - return null; + return Value.ToString (); } - public override IntConstant ConvertToInt () + public override object GetValue () { - return new IntConstant (Value, loc); + return Value; } public override Constant Increment () @@ -768,30 +640,40 @@ namespace Mono.CSharp { } } + public override bool IsOneInteger { + get { + return Value == 1; + } + } + public override bool IsZeroInteger { get { return Value == 0; } } - public override Constant Reduce (bool inCheckedContext, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) { if (target_type == TypeManager.byte_type) { - CheckUnsigned (inCheckedContext, Value); + 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 (inCheckedContext, Value); + 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 (inCheckedContext, Value); + 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 (inCheckedContext, Value); + if (in_checked_context && Value < 0) + throw new OverflowException (); return new ULongConstant ((ulong) Value, Location); } if (target_type == TypeManager.float_type) @@ -799,7 +681,8 @@ namespace Mono.CSharp { if (target_type == TypeManager.double_type) return new DoubleConstant ((double) Value, Location); if (target_type == TypeManager.char_type) { - CheckUnsigned (inCheckedContext, Value); + if (in_checked_context && Value < 0) + throw new OverflowException (); return new CharConstant ((char) Value, Location); } if (target_type == TypeManager.decimal_type) @@ -816,54 +699,34 @@ namespace Mono.CSharp { public ShortConstant (short v, Location loc): base (loc) { - type = TypeManager.short_type; - eclass = ExprClass.Value; Value = v; } - public override void Emit (EmitContext ec) - { - IntLiteral.EmitInt (ec.ig, Value); - } - - public override string AsString () + protected override Expression DoResolve (ResolveContext rc) { - return Value.ToString (); - } - - public override object GetValue () - { - return Value; - } - - public override DoubleConstant ConvertToDouble () - { - return new DoubleConstant (Value, loc); - } - - public override FloatConstant ConvertToFloat () - { - return new FloatConstant (Value, loc); + type = TypeManager.short_type; + eclass = ExprClass.Value; + return this; } - public override ULongConstant ConvertToULong () + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) { - return null; + enc.Stream.Write (Value); } - public override LongConstant ConvertToLong () + public override void Emit (EmitContext ec) { - return new LongConstant (Value, loc); + ec.EmitInt (Value); } - public override UIntConstant ConvertToUInt () + public override string AsString () { - return null; + return Value.ToString (); } - public override IntConstant ConvertToInt () + public override object GetValue () { - return new IntConstant (Value, loc); + return Value; } public override Constant Increment () @@ -886,31 +749,47 @@ namespace Mono.CSharp { return Value < 0; } } + + public override bool IsOneInteger { + get { + return Value == 1; + } + } - public override Constant Reduce (bool inCheckedContext, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) { if (target_type == TypeManager.byte_type) { - CheckRange (inCheckedContext, Value, 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 (inCheckedContext, Value, 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 (inCheckedContext, Value); + 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 (inCheckedContext, Value); + 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 (inCheckedContext, Value); + if (in_checked_context && Value < 0) + throw new OverflowException (); return new ULongConstant ((ulong) Value, Location); } if (target_type == TypeManager.float_type) @@ -918,7 +797,10 @@ namespace Mono.CSharp { if (target_type == TypeManager.double_type) return new DoubleConstant ((double) Value, Location); if (target_type == TypeManager.char_type) { - CheckRange (inCheckedContext, Value, 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) @@ -935,54 +817,34 @@ namespace Mono.CSharp { public UShortConstant (ushort v, Location loc): base (loc) { - type = TypeManager.ushort_type; - eclass = ExprClass.Value; Value = v; } - public override void Emit (EmitContext ec) - { - IntLiteral.EmitInt (ec.ig, Value); - } - - public override string AsString () - { - return Value.ToString (); - } - - public override object GetValue () - { - return Value; - } - - public override DoubleConstant ConvertToDouble () - { - return new DoubleConstant (Value, loc); - } - - public override FloatConstant ConvertToFloat () + protected override Expression DoResolve (ResolveContext rc) { - return new FloatConstant (Value, loc); + type = TypeManager.ushort_type; + eclass = ExprClass.Value; + return this; } - public override ULongConstant ConvertToULong () + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) { - return new ULongConstant (Value, loc); + enc.Stream.Write (Value); } - public override LongConstant ConvertToLong () + public override void Emit (EmitContext ec) { - return new LongConstant (Value, loc); + ec.EmitInt (Value); } - public override UIntConstant ConvertToUInt () + public override string AsString () { - return new UIntConstant (Value, loc); + return Value.ToString (); } - public override IntConstant ConvertToInt () + public override object GetValue () { - return new IntConstant (Value, loc); + return Value; } public override Constant Increment () @@ -1001,23 +863,38 @@ namespace Mono.CSharp { return false; } } + + public override bool IsOneInteger { + get { + return Value == 1; + } + } public override bool IsZeroInteger { get { return Value == 0; } } - public override Constant Reduce (bool inCheckedContext, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) { if (target_type == TypeManager.byte_type) { - CheckRange (inCheckedContext, Value, 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 (inCheckedContext, Value, 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 (inCheckedContext, Value, 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) @@ -1033,7 +910,10 @@ namespace Mono.CSharp { if (target_type == TypeManager.double_type) return new DoubleConstant ((double) Value, Location); if (target_type == TypeManager.char_type) { - CheckRange (inCheckedContext, Value, 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) @@ -1049,66 +929,24 @@ namespace Mono.CSharp { public IntConstant (int v, Location loc): base (loc) { - type = TypeManager.int32_type; - eclass = ExprClass.Value; Value = v; } - static public void EmitInt (ILGenerator ig, int i) + protected override Expression DoResolve (ResolveContext rc) { - switch (i){ - case -1: - ig.Emit (OpCodes.Ldc_I4_M1); - break; - - case 0: - ig.Emit (OpCodes.Ldc_I4_0); - break; - - case 1: - ig.Emit (OpCodes.Ldc_I4_1); - break; - - case 2: - ig.Emit (OpCodes.Ldc_I4_2); - break; - - case 3: - ig.Emit (OpCodes.Ldc_I4_3); - break; - - case 4: - ig.Emit (OpCodes.Ldc_I4_4); - break; - - case 5: - ig.Emit (OpCodes.Ldc_I4_5); - break; - - case 6: - ig.Emit (OpCodes.Ldc_I4_6); - break; - - case 7: - ig.Emit (OpCodes.Ldc_I4_7); - break; - - case 8: - ig.Emit (OpCodes.Ldc_I4_8); - break; + type = TypeManager.int32_type; + eclass = ExprClass.Value; + return this; + } - default: - if (i >= -128 && i <= 127){ - ig.Emit (OpCodes.Ldc_I4_S, (sbyte) i); - } else - ig.Emit (OpCodes.Ldc_I4, i); - break; - } + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) + { + enc.Stream.Write (Value); } public override void Emit (EmitContext ec) { - EmitInt (ec.ig, Value); + ec.EmitInt (Value); } public override string AsString () @@ -1121,47 +959,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); @@ -1178,37 +975,59 @@ namespace Mono.CSharp { return Value < 0; } } + + public override bool IsOneInteger { + get { + return Value == 1; + } + } public override bool IsZeroInteger { get { return Value == 0; } } - public override Constant Reduce (bool inCheckedContext, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) { if (target_type == TypeManager.byte_type) { - CheckRange (inCheckedContext, Value, 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 (inCheckedContext, Value, 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 (inCheckedContext, Value, 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 (inCheckedContext, Value, 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 (inCheckedContext, Value, UInt32.MinValue, UInt32.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 (inCheckedContext, Value); + if (in_checked_context && Value < 0) + throw new OverflowException (); return new ULongConstant ((ulong) Value, Location); } if (target_type == TypeManager.float_type) @@ -1216,7 +1035,10 @@ namespace Mono.CSharp { if (target_type == TypeManager.double_type) return new DoubleConstant ((double) Value, Location); if (target_type == TypeManager.char_type) { - CheckRange (inCheckedContext, Value, 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) @@ -1224,64 +1046,100 @@ namespace Mono.CSharp { return null; } - } - public class UIntConstant : IntegralConstant { - public readonly uint Value; - - public UIntConstant (uint v, Location loc): - base (loc) + public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec type) { - type = TypeManager.uint32_type; - eclass = ExprClass.Value; - Value = v; - } + if (this.type == type) + return this; - public override void Emit (EmitContext ec) - { - IntLiteral.EmitInt (ec.ig, unchecked ((int) Value)); - } + Constant c = TryImplicitIntConversion (type); + if (c != null) + return c.Resolve (rc); - public override string AsString () - { - return Value.ToString (); + return base.ConvertImplicitly (rc, type); } - public override object GetValue () + /// + /// Attempts to perform an implicit constant conversion of the IntConstant + /// into a different data type using casts (See Implicit Constant + /// Expression Conversions) + /// + Constant TryImplicitIntConversion (TypeSpec target_type) { - return Value; + 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 : IntegralConstant { + public readonly uint Value; - public override DoubleConstant ConvertToDouble () + public UIntConstant (uint v, Location loc): + base (loc) { - return new DoubleConstant (Value, loc); + Value = v; } - public override FloatConstant ConvertToFloat () + protected override Expression DoResolve (ResolveContext rc) { - return new FloatConstant (Value, loc); + type = TypeManager.uint32_type; + eclass = ExprClass.Value; + return this; } - public override ULongConstant ConvertToULong () + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) { - return new ULongConstant (Value, loc); + enc.Stream.Write (Value); } - public override LongConstant ConvertToLong () + public override void Emit (EmitContext ec) { - return new LongConstant (Value, loc); + ec.EmitInt (unchecked ((int) Value)); } - public override UIntConstant ConvertToUInt () + public override string AsString () { - return this; + return Value.ToString (); } - public override IntConstant ConvertToInt () + public override object GetValue () { - return null; + return Value; } - + public override Constant Increment () { return new UIntConstant (checked(Value + 1), loc); @@ -1298,31 +1156,52 @@ namespace Mono.CSharp { return false; } } + + public override bool IsOneInteger { + get { + return Value == 1; + } + } public override bool IsZeroInteger { get { return Value == 0; } } - public override Constant Reduce (bool inCheckedContext, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) { if (target_type == TypeManager.byte_type) { - CheckRange (inCheckedContext, Value, 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 (inCheckedContext, Value, 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 (inCheckedContext, Value, 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 (inCheckedContext, Value, 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 (inCheckedContext, Value, 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) @@ -1334,7 +1213,10 @@ namespace Mono.CSharp { if (target_type == TypeManager.double_type) return new DoubleConstant ((double) Value, Location); if (target_type == TypeManager.char_type) { - CheckRange (inCheckedContext, Value, 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) @@ -1350,25 +1232,25 @@ namespace Mono.CSharp { public LongConstant (long v, Location loc): base (loc) + { + Value = v; + } + + protected override Expression DoResolve (ResolveContext rc) { type = TypeManager.int64_type; eclass = ExprClass.Value; - Value = v; + return this; } - public override void Emit (EmitContext ec) + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) { - EmitLong (ec.ig, Value); + enc.Stream.Write (Value); } - static public void EmitLong (ILGenerator ig, long l) + public override void Emit (EmitContext ec) { - if (l >= int.MinValue && l <= int.MaxValue) { - IntLiteral.EmitInt (ig, unchecked ((int) l)); - ig.Emit (OpCodes.Conv_I8); - return; - } - ig.Emit (OpCodes.Ldc_I8, l); + ec.EmitLong (Value); } public override string AsString () @@ -1381,39 +1263,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); @@ -1430,39 +1279,64 @@ namespace Mono.CSharp { return Value < 0; } } + + public override bool IsOneInteger { + get { + return Value == 1; + } + } public override bool IsZeroInteger { get { return Value == 0; } } - public override Constant Reduce (bool inCheckedContext, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) { if (target_type == TypeManager.byte_type) { - CheckRange (inCheckedContext, Value, 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 (inCheckedContext, Value, 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 (inCheckedContext, Value, 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 (inCheckedContext, Value, 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 (inCheckedContext, Value, 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 (inCheckedContext, Value, 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 (inCheckedContext, Value); + if (in_checked_context && Value < 0) + throw new OverflowException (); return new ULongConstant ((ulong) Value, Location); } if (target_type == TypeManager.float_type) @@ -1470,7 +1344,10 @@ namespace Mono.CSharp { if (target_type == TypeManager.double_type) return new DoubleConstant ((double) Value, Location); if (target_type == TypeManager.char_type) { - CheckRange (inCheckedContext, Value, 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) @@ -1479,6 +1356,14 @@ namespace Mono.CSharp { return null; } + public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec type) + { + if (Value >= 0 && type == TypeManager.uint64_type) { + return new ULongConstant ((ulong) Value, loc).Resolve (rc); + } + + return base.ConvertImplicitly (rc, type); + } } public class ULongConstant : IntegralConstant { @@ -1487,56 +1372,34 @@ namespace Mono.CSharp { public ULongConstant (ulong v, Location loc): base (loc) { - type = TypeManager.uint64_type; - eclass = ExprClass.Value; Value = v; } - public override void Emit (EmitContext ec) - { - ILGenerator ig = ec.ig; - - LongLiteral.EmitLong (ig, unchecked ((long) Value)); - } - - public override string AsString () - { - return Value.ToString (); - } - - public override object GetValue () - { - return Value; - } - - public override DoubleConstant ConvertToDouble () - { - return new DoubleConstant (Value, loc); - } - - public override FloatConstant ConvertToFloat () + protected override Expression DoResolve (ResolveContext rc) { - return new FloatConstant (Value, loc); + type = TypeManager.uint64_type; + eclass = ExprClass.Value; + return this; } - public override ULongConstant ConvertToULong () + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) { - return this; + enc.Stream.Write (Value); } - public override LongConstant ConvertToLong () + public override void Emit (EmitContext ec) { - return null; + ec.EmitLong (unchecked ((long) Value)); } - public override UIntConstant ConvertToUInt () + public override string AsString () { - return null; + return Value.ToString (); } - public override IntConstant ConvertToInt () + public override object GetValue () { - return null; + return Value; } public override Constant Increment () @@ -1555,39 +1418,52 @@ namespace Mono.CSharp { return false; } } + + public override bool IsOneInteger { + get { + return Value == 1; + } + } public override bool IsZeroInteger { get { return Value == 0; } } - public override Constant Reduce (bool inCheckedContext, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) { if (target_type == TypeManager.byte_type) { - CheckRange (inCheckedContext, Value, 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 (inCheckedContext, Value, (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 (inCheckedContext, Value, (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 (inCheckedContext, Value, 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 (inCheckedContext, Value, 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 (inCheckedContext, Value, 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 (inCheckedContext, Value, (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) @@ -1595,7 +1471,8 @@ namespace Mono.CSharp { if (target_type == TypeManager.double_type) return new DoubleConstant ((double) Value, Location); if (target_type == TypeManager.char_type) { - CheckRange (inCheckedContext, Value, Char.MaxValue); + if (in_checked_context && Value > Char.MaxValue) + throw new OverflowException (); return new CharConstant ((char) Value, Location); } if (target_type == TypeManager.decimal_type) @@ -1607,59 +1484,39 @@ namespace Mono.CSharp { } public class FloatConstant : Constant { - public readonly float Value; + public float Value; public FloatConstant (float v, Location loc): base (loc) { - type = TypeManager.float_type; - eclass = ExprClass.Value; Value = v; } - public override void Emit (EmitContext ec) - { - ec.ig.Emit (OpCodes.Ldc_R4, Value); - } - - public override string AsString () - { - return Value.ToString (); - } - - public override object GetValue () - { - return Value; - } - - public override DoubleConstant ConvertToDouble () - { - return new DoubleConstant (Value, loc); - } - - public override FloatConstant ConvertToFloat () + protected override Expression DoResolve (ResolveContext rc) { + type = TypeManager.float_type; + eclass = ExprClass.Value; return this; } - public override LongConstant ConvertToLong () + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) { - return null; + enc.Stream.Write (Value); } - public override UIntConstant ConvertToUInt () + public override void Emit (EmitContext ec) { - return null; + ec.Emit (OpCodes.Ldc_R4, Value); } - public override IntConstant ConvertToInt () + public override string AsString () { - return null; + return Value.ToString (); } - public override Constant Increment () + public override object GetValue () { - return new FloatConstant (checked(Value + 1), loc); + return Value; } public override bool IsDefaultValue { @@ -1674,44 +1531,71 @@ namespace Mono.CSharp { } } - public override Constant Reduce (bool inCheckedContext, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) { if (target_type == TypeManager.byte_type) { - CheckRange (inCheckedContext, Value, byte.MinValue, byte.MaxValue); + if (in_checked_context){ + 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) { - CheckRange (inCheckedContext, Value, sbyte.MinValue, sbyte.MaxValue); + if (in_checked_context){ + 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) { - CheckRange (inCheckedContext, Value, short.MinValue, short.MaxValue); + if (in_checked_context){ + 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) { - CheckRange (inCheckedContext, Value, ushort.MinValue, ushort.MaxValue); + if (in_checked_context){ + 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) { - CheckRange (inCheckedContext, Value, int.MinValue, int.MaxValue); + if (in_checked_context){ + 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) { - CheckRange (inCheckedContext, Value, uint.MinValue, uint.MaxValue); + if (in_checked_context){ + 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) { - CheckRange (inCheckedContext, Value, long.MinValue, long.MaxValue); + if (in_checked_context){ + 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) { - CheckRange (inCheckedContext, Value, ulong.MinValue, ulong.MaxValue); + if (in_checked_context){ + if (Value < ulong.MinValue || Value > ulong.MaxValue || float.IsNaN (Value)) + 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) { - CheckRange (inCheckedContext, Value, char.MinValue, char.MaxValue); + if (in_checked_context){ + 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.decimal_type) @@ -1723,64 +1607,39 @@ namespace Mono.CSharp { } public class DoubleConstant : Constant { - public readonly double Value; + public double Value; public DoubleConstant (double v, Location loc): base (loc) { - type = TypeManager.double_type; - eclass = ExprClass.Value; Value = v; } - public override void Emit (EmitContext ec) - { - ec.ig.Emit (OpCodes.Ldc_R8, Value); - } - - public override string AsString () - { - return Value.ToString (); - } - - public override object GetValue () - { - return Value; - } - - public override DoubleConstant ConvertToDouble () + protected override Expression DoResolve (ResolveContext rc) { + type = TypeManager.double_type; + eclass = ExprClass.Value; return this; } - public override FloatConstant ConvertToFloat () + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) { - return null; + enc.Stream.Write (Value); } - public override ULongConstant ConvertToULong () - { - return null; - } - - public override LongConstant ConvertToLong () - { - return null; - } - - public override UIntConstant ConvertToUInt () + public override void Emit (EmitContext ec) { - return null; + ec.Emit (OpCodes.Ldc_R8, Value); } - public override IntConstant ConvertToInt () + public override string AsString () { - return null; + return Value.ToString (); } - public override Constant Increment () + public override object GetValue () { - return new DoubleConstant (checked(Value + 1), loc); + return Value; } public override bool IsDefaultValue { @@ -1795,44 +1654,71 @@ namespace Mono.CSharp { } } - public override Constant Reduce (bool inCheckedContext, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) { if (target_type == TypeManager.byte_type) { - CheckRange (inCheckedContext, Value, Byte.MinValue, Byte.MaxValue); + if (in_checked_context){ + 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) { - CheckRange (inCheckedContext, Value, SByte.MinValue, SByte.MaxValue); + if (in_checked_context){ + 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) { - CheckRange (inCheckedContext, Value, short.MinValue, short.MaxValue); + if (in_checked_context){ + 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) { - CheckRange (inCheckedContext, Value, ushort.MinValue, ushort.MaxValue); + if (in_checked_context){ + 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) { - CheckRange (inCheckedContext, Value, int.MinValue, int.MaxValue); + if (in_checked_context){ + 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) { - CheckRange (inCheckedContext, Value, uint.MinValue, uint.MaxValue); + if (in_checked_context){ + 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) { - CheckRange (inCheckedContext, Value, long.MinValue, long.MaxValue); + if (in_checked_context){ + 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) { - CheckRange (inCheckedContext, Value, ulong.MinValue, ulong.MaxValue); + if (in_checked_context){ + if (Value < ulong.MinValue || Value > ulong.MaxValue || double.IsNaN (Value)) + 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 (inCheckedContext, Value, char.MinValue, char.MaxValue); + if (in_checked_context){ + if (Value < (double) char.MinValue || Value > (double) char.MaxValue || double.IsNaN (Value)) + throw new OverflowException (); + } return new CharConstant ((char) Value, Location); } if (target_type == TypeManager.decimal_type) @@ -1849,14 +1735,19 @@ namespace Mono.CSharp { public DecimalConstant (decimal d, Location loc): base (loc) { - type = TypeManager.decimal_type; - eclass = ExprClass.Value; Value = d; } override public string AsString () { - return Value.ToString (); + return Value.ToString () + "M"; + } + + protected override Expression DoResolve (ResolveContext rc) + { + type = TypeManager.decimal_type; + eclass = ExprClass.Value; + return this; } public override object GetValue () @@ -1866,40 +1757,59 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { - ILGenerator ig = ec.ig; - - int [] words = Decimal.GetBits (Value); + 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; - } + if (power == 0) { + if (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); - - // - // FIXME: we could optimize this, and call a better - // constructor - // + if (TypeManager.void_decimal_ctor_int_arg == null) + return; + } + + ec.EmitInt ((int) Value); + ec.Emit (OpCodes.Newobj, TypeManager.void_decimal_ctor_int_arg); + return; + } + + if (Value <= long.MaxValue && Value >= long.MinValue) { + if (TypeManager.void_decimal_ctor_long_arg == null) { + TypeManager.void_decimal_ctor_long_arg = TypeManager.GetPredefinedConstructor ( + TypeManager.decimal_type, loc, TypeManager.int64_type); - IntConstant.EmitInt (ig, words [0]); - IntConstant.EmitInt (ig, words [1]); - IntConstant.EmitInt (ig, words [2]); + if (TypeManager.void_decimal_ctor_long_arg == null) + return; + } + + ec.EmitLong ((long) Value); + ec.Emit (OpCodes.Newobj, TypeManager.void_decimal_ctor_long_arg); + return; + } + } + + ec.EmitInt (words [0]); + ec.EmitInt (words [1]); + ec.EmitInt (words [2]); // sign - IntConstant.EmitInt (ig, words [3] >> 31); + ec.EmitInt (words [3] >> 31); // power - IntConstant.EmitInt (ig, power); + ec.EmitInt (power); - ig.Emit (OpCodes.Newobj, TypeManager.void_decimal_ctor_five_args); - } + 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); - public override Constant Increment () - { - return new DecimalConstant (checked (Value + 1), loc); + if (TypeManager.void_decimal_ctor_five_args == null) + return; + } + + ec.Emit (OpCodes.Newobj, TypeManager.void_decimal_ctor_five_args); } public override bool IsDefaultValue { @@ -1914,7 +1824,7 @@ namespace Mono.CSharp { } } - public override Constant Reduce (bool inCheckedContext, Type target_type) + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) { if (target_type == TypeManager.sbyte_type) return new SByteConstant ((sbyte)Value, loc); @@ -1950,8 +1860,6 @@ namespace Mono.CSharp { public StringConstant (string s, Location loc): base (loc) { - type = TypeManager.string_type; - eclass = ExprClass.Value; Value = s; } @@ -1961,6 +1869,13 @@ namespace Mono.CSharp { return "\"" + Value + "\""; } + protected override Expression DoResolve (ResolveContext rc) + { + type = TypeManager.string_type; + eclass = ExprClass.Value; + return this; + } + public override object GetValue () { return Value; @@ -1968,15 +1883,35 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { - if (Value == null) - ec.ig.Emit (OpCodes.Ldnull); - else - ec.ig.Emit (OpCodes.Ldstr, Value); + if (Value == null) { + ec.Emit (OpCodes.Ldnull); + return; + } + + // + // Use string.Empty for both literals and constants even if + // it's not allowed at language level + // + if (Value.Length == 0 && RootContext.Optimize && !TypeManager.IsEqual (ec.CurrentType, TypeManager.string_type)) { + if (TypeManager.string_empty == null) + TypeManager.string_empty = TypeManager.GetPredefinedField (TypeManager.string_type, "Empty", loc, TypeManager.string_type); + + if (TypeManager.string_empty != null) { + ec.Emit (OpCodes.Ldsfld, TypeManager.string_empty); + return; + } + } + + ec.Emit (OpCodes.Ldstr, Value); } - public override Constant Increment () + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) { - throw new NotSupportedException (); + // cast to object + if (type != targetType) + enc.Encode (type); + + enc.Encode (Value); } public override bool IsDefaultValue { @@ -1991,12 +1926,205 @@ namespace Mono.CSharp { } } - public override Constant Reduce (bool inCheckedContext, Type target_type) + public override bool IsNull { + get { + return IsDefaultValue; + } + } + + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) { return null; } } -} + // + // Null constant can have its own type, think of `default (Foo)' + // + public class NullConstant : Constant + { + public NullConstant (TypeSpec type, Location loc) + : base (loc) + { + eclass = ExprClass.Value; + this.type = type; + } + + public override string AsString () + { + return GetSignatureForError (); + } + + public override Expression CreateExpressionTree (ResolveContext ec) + { + if (type == InternalType.Null || type == TypeManager.object_type) { + // Optimized version, also avoids referencing literal internal type + Arguments args = new Arguments (1); + args.Add (new Argument (this)); + return CreateExpressionFactoryCall (ec, "Constant", args); + } + + return base.CreateExpressionTree (ec); + } + + protected override Expression DoResolve (ResolveContext ec) + { + return this; + } + + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) + { + // Type it as string cast + if (targetType == TypeManager.object_type || targetType == TypeManager.null_type) + enc.Encode (TypeManager.string_type); + + var ac = targetType as ArrayContainer; + if (ac != null) { + if (ac.Rank != 1) + base.EncodeAttributeValue (rc, enc, targetType); + else + enc.Stream.Write (uint.MaxValue); + } else { + enc.Stream.Write (byte.MaxValue); + } + } + + public override void Emit (EmitContext ec) + { + ec.Emit (OpCodes.Ldnull); + + // Only to make verifier happy + if (TypeManager.IsGenericParameter (type)) + ec.Emit (OpCodes.Unbox_Any, type); + } + + public override string ExprClassName { + get { + return GetSignatureForError (); + } + } + + public override string GetSignatureForError () + { + return "null"; + } + + public override Constant ConvertExplicitly (bool inCheckedContext, TypeSpec targetType) + { + if (targetType.IsPointer) { + if (IsLiteral || this is NullPointer) + return new EmptyConstantCast (new NullPointer (loc), targetType); + + return null; + } + + // Exlude internal compiler types + if (targetType == InternalType.AnonymousMethod) + return null; + + if (!IsLiteral && !Convert.ImplicitStandardConversionExists (this, targetType)) + return null; + + if (TypeManager.IsReferenceType (targetType)) + return new NullConstant (targetType, loc); + + if (TypeManager.IsNullableType (targetType)) + return Nullable.LiftedNull.Create (targetType, loc); + + return null; + } + + public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec targetType) + { + return ConvertExplicitly (false, targetType); + } + + public override object GetValue () + { + return null; + } + + public override bool IsDefaultValue { + get { return true; } + } + + public override bool IsNegative { + get { return false; } + } + + public override bool IsNull { + get { return true; } + } + + public override bool IsZeroInteger { + get { return true; } + } + } + + /// + /// 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. + /// + 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; + } + + public override string AsString () + { + return value.AsString (); + } + + protected override Expression DoResolve (ResolveContext rc) + { + value = value.Resolve (rc); + + type = value.Type; + eclass = ExprClass.Value; + return this; + } + + 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 bool IsNegative { + get { return value.IsNegative; } + } + public override bool IsZeroInteger { + get { return value.IsZeroInteger; } + } + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec 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); + } + } +}