X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;ds=sidebyside;f=mcs%2Fmcs%2Fconstant.cs;h=d37e0f01bf37b55a738b4cc3c8b06dcb89bfc67d;hb=bff1c7a08cc189211e458561de52e76b403912f5;hp=89d6da3f160adb1670024be0794330cdd84b56e1;hpb=03682cb49e43623a4e042c1a13d1870313cc3876;p=mono.git diff --git a/mcs/mcs/constant.cs b/mcs/mcs/constant.cs index 89d6da3f160..d37e0f01bf3 100644 --- a/mcs/mcs/constant.cs +++ b/mcs/mcs/constant.cs @@ -3,10 +3,11 @@ // // Author: // Miguel de Icaza (miguel@ximian.com) -// Marek Safar (marek.safar@seznam.cz) +// Marek Safar (marek.safar@gmail.com) // // Copyright 2001-2003 Ximian, Inc. // Copyright 2003-2008 Novell, Inc. +// Copyright 2011-2013 Xamarin Inc // using System; @@ -57,33 +58,38 @@ namespace Mono.CSharp { } #endif - public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl) + public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl) { if (!expl && IsLiteral && BuiltinTypeSpec.IsPrimitiveTypeOrDecimal (target) && BuiltinTypeSpec.IsPrimitiveTypeOrDecimal (type)) { ec.Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'", - GetValueAsLiteral (), TypeManager.CSharpName (target)); + GetValueAsLiteral (), target.GetSignatureForError ()); } else { - base.Error_ValueCannotBeConverted (ec, loc, target, expl); + base.Error_ValueCannotBeConverted (ec, target, expl); } } - public Constant ImplicitConversionRequired (ResolveContext ec, TypeSpec type, Location loc) + public Constant ImplicitConversionRequired (ResolveContext ec, TypeSpec type) { Constant c = ConvertImplicitly (type); if (c == null) - Error_ValueCannotBeConverted (ec, loc, type, false); + Error_ValueCannotBeConverted (ec, type, false); return c; } + public override bool ContainsEmitWithAwait () + { + return false; + } + public virtual Constant ConvertImplicitly (TypeSpec type) { if (this.type == type) return this; - if (Convert.ImplicitNumericConversion (this, type) == null) + if (!Convert.ImplicitNumericConversionExists (this.type, type)) return null; bool fail; @@ -94,20 +100,15 @@ namespace Mono.CSharp { // reached, by calling Convert.ImplicitStandardConversionExists // throw new InternalErrorException ("Missing constant conversion between `{0}' and `{1}'", - TypeManager.CSharpName (Type), TypeManager.CSharpName (type)); + Type.GetSignatureForError (), type.GetSignatureForError ()); } - return CreateConstant (type, constant_value, loc); + return CreateConstantFromValue (type, constant_value, loc); } // // Returns a constant instance based on Type // - public static Constant CreateConstant (TypeSpec t, object v, Location loc) - { - return CreateConstantFromValue (t, v, loc); - } - public static Constant CreateConstantFromValue (TypeSpec t, object v, Location loc) { switch (t.BuiltinType) { @@ -150,14 +151,99 @@ namespace Mono.CSharp { if (t.IsNullableType) return Nullable.LiftedNull.Create (t, loc); - if (TypeManager.IsReferenceType (t)) + if (TypeSpec.IsReferenceType (t)) + return new NullConstant (t, loc); + } + +#if STATIC + throw new InternalErrorException ("Constant value `{0}' has unexpected underlying type `{1}'", v, t.GetSignatureForError ()); +#else + return null; +#endif + } + + // + // Returns a constant instance based on value and type. This is probing version of + // CreateConstantFromValue + // + public static Constant ExtractConstantFromValue (TypeSpec t, object v, Location loc) + { + switch (t.BuiltinType) { + case BuiltinTypeSpec.Type.Int: + if (v is int) + return new IntConstant (t, (int) v, loc); + break; + case BuiltinTypeSpec.Type.String: + if (v is string) + return new StringConstant (t, (string) v, loc); + break; + case BuiltinTypeSpec.Type.UInt: + if (v is uint) + return new UIntConstant (t, (uint) v, loc); + break; + case BuiltinTypeSpec.Type.Long: + if (v is long) + return new LongConstant (t, (long) v, loc); + break; + case BuiltinTypeSpec.Type.ULong: + if (v is ulong) + return new ULongConstant (t, (ulong) v, loc); + break; + case BuiltinTypeSpec.Type.Float: + if (v is float) + return new FloatConstant (t, (float) v, loc); + break; + case BuiltinTypeSpec.Type.Double: + if (v is double) + return new DoubleConstant (t, (double) v, loc); + break; + case BuiltinTypeSpec.Type.Short: + if (v is short) + return new ShortConstant (t, (short) v, loc); + break; + case BuiltinTypeSpec.Type.UShort: + if (v is ushort) + return new UShortConstant (t, (ushort) v, loc); + break; + case BuiltinTypeSpec.Type.SByte: + if (v is sbyte) + return new SByteConstant (t, (sbyte) v, loc); + break; + case BuiltinTypeSpec.Type.Byte: + if (v is byte) + return new ByteConstant (t, (byte) v, loc); + break; + case BuiltinTypeSpec.Type.Char: + if (v is char) + return new CharConstant (t, (char) v, loc); + break; + case BuiltinTypeSpec.Type.Bool: + if (v is bool) + return new BoolConstant (t, (bool) v, loc); + break; + case BuiltinTypeSpec.Type.Decimal: + if (v is decimal) + return new DecimalConstant (t, (decimal) v, loc); + break; + } + + if (t.IsEnum) { + var real_type = EnumSpec.GetUnderlyingType (t); + return new EnumConstant (CreateConstantFromValue (real_type, v, loc), t); + } + + if (v == null) { + if (t.IsNullableType) + return Nullable.LiftedNull.Create (t, loc); + + if (TypeSpec.IsReferenceType (t)) return new NullConstant (t, loc); } - throw new InternalErrorException ("Constant value `{0}' has unexpected underlying type `{1}'", - v, TypeManager.CSharpName (t)); + return null; } + public override Expression CreateExpressionTree (ResolveContext ec) { Arguments args = new Arguments (2); @@ -242,35 +328,52 @@ namespace Mono.CSharp { return this; } - /// - /// Attempts to do a compile-time folding of a constant cast. - /// - public Constant TryReduce (ResolveContext ec, TypeSpec target_type, Location loc) + // + // Attempts to do a compile-time folding of a constant cast and handles + // error reporting for constant overlows only, on normal conversion + // errors returns null + // + public Constant Reduce (ResolveContext ec, TypeSpec target_type) { try { - return TryReduce (ec, target_type); - } - catch (OverflowException) { + return TryReduceConstant (ec, target_type); + } catch (OverflowException) { if (ec.ConstantCheckState && Type.BuiltinType != BuiltinTypeSpec.Type.Decimal) { ec.Report.Error (221, loc, "Constant value `{0}' cannot be converted to a `{1}' (use `unchecked' syntax to override)", GetValueAsLiteral (), target_type.GetSignatureForError ()); } else { - Error_ValueCannotBeConverted (ec, loc, target_type, false); + Error_ValueCannotBeConverted (ec, target_type, false); } return New.Constantify (target_type, loc); } } - Constant TryReduce (ResolveContext ec, TypeSpec target_type) + public Constant TryReduce (ResolveContext rc, TypeSpec targetType) { - if (Type == target_type) + try { + return TryReduceConstant (rc, targetType); + } catch (OverflowException) { + return null; + } + } + + Constant TryReduceConstant (ResolveContext ec, TypeSpec target_type) + { + if (Type == target_type) { + // + // Reducing literal value produces a new constant. Syntactically 10 is not same as (int)10 + // + if (IsLiteral) + return CreateConstantFromValue (target_type, GetValue (), loc); + return this; + } Constant c; - if (TypeManager.IsEnumType (target_type)) { - c = TryReduce (ec, EnumSpec.GetUnderlyingType (target_type)); + if (target_type.IsEnum) { + c = TryReduceConstant (ec, EnumSpec.GetUnderlyingType (target_type)); if (c == null) return null; @@ -309,7 +412,13 @@ namespace Mono.CSharp { public virtual bool IsOneInteger { get { return false; } - } + } + + public override bool IsSideEffectFree { + get { + return true; + } + } // // Returns true iff 1) the stack type of this is one of Object, @@ -360,16 +469,16 @@ namespace Mono.CSharp { eclass = ExprClass.Value; } - public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl) + public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl) { try { ConvertExplicitly (true, target); - base.Error_ValueCannotBeConverted (ec, loc, target, expl); + base.Error_ValueCannotBeConverted (ec, target, expl); } catch { ec.Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'", - GetValue ().ToString (), TypeManager.CSharpName (target)); + GetValue ().ToString (), target.GetSignatureForError ()); } } @@ -421,9 +530,9 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { if (Value) - ec.Emit (OpCodes.Ldc_I4_1); + ec.EmitInt (1); else - ec.Emit (OpCodes.Ldc_I4_0); + ec.EmitInt (0); } public override bool IsDefaultValue { @@ -1537,20 +1646,32 @@ namespace Mono.CSharp { } public class FloatConstant : Constant { - public readonly float Value; + // + // Store constant value as double because float constant operations + // need to work on double value to match JIT + // + public readonly double DoubleValue; - public FloatConstant (BuiltinTypes types, float v, Location loc) + public FloatConstant (BuiltinTypes types, double v, Location loc) : this (types.Float, v, loc) { } - public FloatConstant (TypeSpec type, float v, Location loc) + public FloatConstant (TypeSpec type, double v, Location loc) : base (loc) { this.type = type; eclass = ExprClass.Value; - Value = v; + DoubleValue = v; + } + + public override Constant ConvertImplicitly (TypeSpec type) + { + if (type.BuiltinType == BuiltinTypeSpec.Type.Double) + return new DoubleConstant (type, DoubleValue, loc); + + return base.ConvertImplicitly (type); } public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) @@ -1563,6 +1684,12 @@ namespace Mono.CSharp { ec.Emit (OpCodes.Ldc_R4, Value); } + public float Value { + get { + return (float) DoubleValue; + } + } + public override object GetValue () { return Value; @@ -1598,59 +1725,59 @@ namespace Mono.CSharp { if (Value < byte.MinValue || Value > byte.MaxValue || float.IsNaN (Value)) throw new OverflowException (); } - return new ByteConstant (target_type, (byte) Value, Location); + return new ByteConstant (target_type, (byte) DoubleValue, Location); case BuiltinTypeSpec.Type.SByte: if (in_checked_context) { if (Value < sbyte.MinValue || Value > sbyte.MaxValue || float.IsNaN (Value)) throw new OverflowException (); } - return new SByteConstant (target_type, (sbyte) Value, Location); + return new SByteConstant (target_type, (sbyte) DoubleValue, Location); case BuiltinTypeSpec.Type.Short: if (in_checked_context) { if (Value < short.MinValue || Value > short.MaxValue || float.IsNaN (Value)) throw new OverflowException (); } - return new ShortConstant (target_type, (short) Value, Location); + return new ShortConstant (target_type, (short) DoubleValue, Location); case BuiltinTypeSpec.Type.UShort: if (in_checked_context) { if (Value < ushort.MinValue || Value > ushort.MaxValue || float.IsNaN (Value)) throw new OverflowException (); } - return new UShortConstant (target_type, (ushort) Value, Location); + return new UShortConstant (target_type, (ushort) DoubleValue, Location); case BuiltinTypeSpec.Type.Int: if (in_checked_context) { if (Value < int.MinValue || Value > int.MaxValue || float.IsNaN (Value)) throw new OverflowException (); } - return new IntConstant (target_type, (int) Value, Location); + return new IntConstant (target_type, (int) DoubleValue, Location); case BuiltinTypeSpec.Type.UInt: if (in_checked_context) { if (Value < uint.MinValue || Value > uint.MaxValue || float.IsNaN (Value)) throw new OverflowException (); } - return new UIntConstant (target_type, (uint) Value, Location); + return new UIntConstant (target_type, (uint) DoubleValue, Location); case BuiltinTypeSpec.Type.Long: if (in_checked_context) { if (Value < long.MinValue || Value > long.MaxValue || float.IsNaN (Value)) throw new OverflowException (); } - return new LongConstant (target_type, (long) Value, Location); + return new LongConstant (target_type, (long) DoubleValue, Location); case BuiltinTypeSpec.Type.ULong: if (in_checked_context) { if (Value < ulong.MinValue || Value > ulong.MaxValue || float.IsNaN (Value)) throw new OverflowException (); } - return new ULongConstant (target_type, (ulong) Value, Location); + return new ULongConstant (target_type, (ulong) DoubleValue, Location); case BuiltinTypeSpec.Type.Double: - return new DoubleConstant (target_type, (double) Value, Location); + return new DoubleConstant (target_type, DoubleValue, Location); case BuiltinTypeSpec.Type.Char: if (in_checked_context) { if (Value < (float) char.MinValue || Value > (float) char.MaxValue || float.IsNaN (Value)) throw new OverflowException (); } - return new CharConstant (target_type, (char) Value, Location); + return new CharConstant (target_type, (char) DoubleValue, Location); case BuiltinTypeSpec.Type.Decimal: - return new DecimalConstant (target_type, (decimal) Value, Location); + return new DecimalConstant (target_type, (decimal) DoubleValue, Location); } return null; @@ -1939,7 +2066,7 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { if (Value == null) { - ec.Emit (OpCodes.Ldnull); + ec.EmitNull (); return; } @@ -1992,6 +2119,14 @@ namespace Mono.CSharp { { return null; } + + public override Constant ConvertImplicitly (TypeSpec type) + { + if (IsDefaultValue && type.BuiltinType == BuiltinTypeSpec.Type.Object) + return new NullConstant (type, loc); + + return base.ConvertImplicitly (type); + } } // @@ -2044,7 +2179,7 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { - ec.Emit (OpCodes.Ldnull); + ec.EmitNull (); // Only to make verifier happy if (type.IsGenericParameter) @@ -2073,7 +2208,7 @@ namespace Mono.CSharp { if (!IsLiteral && !Convert.ImplicitStandardConversionExists (this, targetType)) return null; - if (TypeManager.IsReferenceType (targetType)) + if (TypeSpec.IsReferenceType (targetType)) return new NullConstant (targetType, loc); if (targetType.IsNullableType) @@ -2146,7 +2281,7 @@ namespace Mono.CSharp { // // Emits null pointer // - ec.Emit (OpCodes.Ldc_I4_0); + ec.EmitInt (0); ec.Emit (OpCodes.Conv_U); } } @@ -2156,7 +2291,8 @@ namespace Mono.CSharp { /// used by BitwiseAnd to ensure that the second expression is invoked /// regardless of the value of the left side. /// - public class SideEffectConstant : Constant { + public class SideEffectConstant : Constant + { public readonly Constant value; Expression side_effect; @@ -2172,6 +2308,12 @@ namespace Mono.CSharp { this.side_effect = side_effect; } + public override bool IsSideEffectFree { + get { + return false; + } + } + public override object GetValue () { return value.GetValue ();