X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fconst.cs;h=1e980404b27de7511fd506e57e431fa0fac349d0;hb=18e6c685c30271b4236fc680ceadf8257ec4ca03;hp=ce276fd6160d2b767d9d6f10338f383897ec78a1;hpb=e4cadfcaf4f64ca630eb7082698aea1d774f76b6;p=mono.git diff --git a/mcs/mcs/const.cs b/mcs/mcs/const.cs old mode 100755 new mode 100644 index ce276fd6160..1e980404b27 --- a/mcs/mcs/const.cs +++ b/mcs/mcs/const.cs @@ -3,20 +3,12 @@ // // Author: // Miguel de Icaza (miguel@ximian.com) +// Marek Safar (marek.safar@seznam.cz) // // (C) 2001 Ximian, Inc. // // -// -// This is needed because the following situation arises: -// -// The FieldBuilder is declared with the real type for an enumeration -// -// When we attempt to set the value for the constant, the FieldBuilder.SetConstant -// function aborts because it requires its argument to be of the same type -// - namespace Mono.CSharp { using System; @@ -24,15 +16,16 @@ namespace Mono.CSharp { using System.Reflection.Emit; using System.Collections; - public class Const : FieldBase { - public Expression Expr; - EmitContext const_ec; - - bool resolved = false; - object ConstantValue = null; - Type type; + public interface IConstant + { + void CheckObsoleteness (Location loc); + bool ResolveValue (); + Constant Value { get; } + } - bool in_transit = false; + public class Const : FieldMember, IConstant { + Constant value; + bool in_transit; public const int AllowedModifiers = Modifiers.NEW | @@ -41,257 +34,212 @@ namespace Mono.CSharp { Modifiers.INTERNAL | Modifiers.PRIVATE; - public Const (TypeContainer parent, Expression constant_type, string name, + public Const (DeclSpace parent, Expression constant_type, string name, Expression expr, int mod_flags, Attributes attrs, Location loc) - : base (parent, constant_type, mod_flags, AllowedModifiers, name, - null, attrs, loc) + : base (parent, constant_type, mod_flags, AllowedModifiers, + new MemberName (name, loc), attrs) { - Expr = expr; + initializer = expr; + ModFlags |= Modifiers.STATIC; } - public FieldAttributes FieldAttr { - get { - return FieldAttributes.Literal | FieldAttributes.Static | - Modifiers.FieldAttr (ModFlags) ; - } - } - -#if DEBUG - void dump_tree (Type t) + protected override bool CheckBase () { - Console.WriteLine ("Dumping hierarchy"); - while (t != null){ - Console.WriteLine (" " + t.FullName + " " + - (t.GetType ().IsEnum ? "yes" : "no")); - t = t.BaseType; - } + // Constant.Define can be called when the parent type hasn't yet been populated + // and it's base types need not have been populated. So, we defer this check + // to the second time Define () is called on this member. + if (ParentContainer.BaseCache == null) + return true; + return base.CheckBase (); } -#endif /// /// Defines the constant in the @parent /// public override bool Define () { - type = Parent.ResolveType (Type, false, Location); + // Make Define () idempotent, but ensure that the error check happens. + if (FieldBuilder != null) + return base.CheckBase (); - if (type == null) + if (!base.Define ()) return false; - const_ec = new EmitContext (Parent, Location, null, type, ModFlags); - - Type ttype = type; + Type ttype = MemberType; while (ttype.IsArray) ttype = TypeManager.GetElementType (ttype); - - if (!TypeManager.IsBuiltinType (ttype) && - (!ttype.IsSubclassOf (TypeManager.enum_type))) { - Report.Error ( - -3, Location, - "Constant type is not valid (only system types are allowed)"); - return false; - } - if (!CheckBase ()) - return false; + FieldAttributes field_attr = FieldAttributes.Static | Modifiers.FieldAttr (ModFlags); + // Decimals cannot be emitted into the constant blob. So, convert to 'readonly'. + if (ttype == TypeManager.decimal_type) { + field_attr |= FieldAttributes.InitOnly; + ParentContainer.RegisterFieldForInitialization (this); + } + else { + field_attr |= FieldAttributes.Literal; + } - FieldBuilder = Parent.TypeBuilder.DefineField (Name, type, FieldAttr); + FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType, field_attr); TypeManager.RegisterConstant (FieldBuilder, this); return true; } - - // - // Changes the type of the constant expression `expr' to the Type `type' - // Returns null on failure. - // - public static Constant ChangeType (Location loc, Constant expr, Type type) + + /// + /// Emits the field value by evaluating the expression + /// + public override void Emit () { - if (type == TypeManager.object_type) - return expr; + if (!ResolveValue ()) + return; + + if (value.Type == TypeManager.decimal_type) { + Decimal d = ((DecimalConstant)value).Value; + int[] bits = Decimal.GetBits (d); + object[] args = new object[] { (byte)(bits [3] >> 16), (byte)(bits [3] >> 31), (uint)bits [2], (uint)bits [1], (uint)bits [0] }; + CustomAttributeBuilder cab = new CustomAttributeBuilder (TypeManager.decimal_constant_attribute_ctor, args); + FieldBuilder.SetCustomAttribute (cab); + } + else{ + FieldBuilder.SetConstant (value.GetTypedValue ()); + } - bool fail; + base.Emit (); + } - // from the null type to any reference-type. - if (expr is NullLiteral && !type.IsValueType && !TypeManager.IsEnumType (type)) - return NullLiteral.Null; + public static void Error_ExpressionMustBeConstant (Location loc, string e_name) + { + Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name); + } - if (!Convert.ImplicitStandardConversionExists (expr, type)){ - Convert.Error_CannotImplicitConversion (loc, expr.Type, type); - return null; - } - - object constant_value = TypeManager.ChangeType (expr.GetValue (), type, out fail); - if (fail){ - Convert.Error_CannotImplicitConversion (loc, expr.Type, type); - - // - // 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}", expr.Type, type)); - } + public static void Error_CyclicDeclaration (MemberCore mc) + { + Report.Error (110, mc.Location, "The evaluation of the constant value for `{0}' involves a circular definition", + mc.GetSignatureForError ()); + } - Constant retval; - if (type == TypeManager.int32_type) - retval = new IntConstant ((int) constant_value); - else if (type == TypeManager.uint32_type) - retval = new UIntConstant ((uint) constant_value); - else if (type == TypeManager.int64_type) - retval = new LongConstant ((long) constant_value); - else if (type == TypeManager.uint64_type) - retval = new ULongConstant ((ulong) constant_value); - else if (type == TypeManager.float_type) - retval = new FloatConstant ((float) constant_value); - else if (type == TypeManager.double_type) - retval = new DoubleConstant ((double) constant_value); - else if (type == TypeManager.string_type) - retval = new StringConstant ((string) constant_value); - else if (type == TypeManager.short_type) - retval = new ShortConstant ((short) constant_value); - else if (type == TypeManager.ushort_type) - retval = new UShortConstant ((ushort) constant_value); - else if (type == TypeManager.sbyte_type) - retval = new SByteConstant ((sbyte) constant_value); - else if (type == TypeManager.byte_type) - retval = new ByteConstant ((byte) constant_value); - else if (type == TypeManager.char_type) - retval = new CharConstant ((char) constant_value); - else if (type == TypeManager.bool_type) - retval = new BoolConstant ((bool) constant_value); - else - throw new Exception ("LookupConstantValue: Unhandled constant type: " + type); - - return retval; + public static void Error_ConstantCanBeInitializedWithNullOnly (Location loc, string name) + { + Report.Error (134, loc, "`{0}': the constant of reference type other than string can only be initialized with null", + name); } - - /// - /// Looks up the value of a constant field. Defines it if it hasn't - /// already been. Similar to LookupEnumValue in spirit. - /// - public bool LookupConstantValue (out object value) + + #region IConstant Members + + public bool ResolveValue () { - if (resolved) { - value = ConstantValue; + if (value != null) return true; - } + SetMemberIsUsed (); if (in_transit) { - Report.Error (110, Location, - "The evaluation of the constant value for `" + - Name + "' involves a circular definition."); - value = null; + Error_CyclicDeclaration (this); + // Suppress cyclic errors + value = New.Constantify (MemberType); return false; } in_transit = true; - int errors = Report.Errors; + // TODO: IResolveContext here + EmitContext ec = new EmitContext (this, Parent, Location, null, MemberType, ModFlags); + value = initializer.ResolveAsConstant (ec, this); + in_transit = false; - // - // We might have cleared Expr ourselves in a recursive definition - // - if (Expr == null){ - value = null; + if (value == null) return false; - } - Expr = Expr.Resolve (const_ec); - - in_transit = false; + value = value.ToType (MemberType, Location); + if (value == null) + return false; - if (Expr == null) { - if (errors == Report.Errors) - Report.Error (150, Location, "A constant value is expected"); - value = null; + if (!MemberType.IsValueType && MemberType != TypeManager.string_type && !value.IsDefaultValue) { + Error_ConstantCanBeInitializedWithNullOnly (Location, GetSignatureForError ()); return false; } - Expression real_expr = Expr; - - Constant ce = Expr as Constant; - if (ce == null){ - UnCheckedExpr un_expr = Expr as UnCheckedExpr; - CheckedExpr ch_expr = Expr as CheckedExpr; - EmptyCast ec_expr = Expr as EmptyCast; - - if ((un_expr != null) && (un_expr.Expr is Constant)) - Expr = un_expr.Expr; - else if ((ch_expr != null) && (ch_expr.Expr is Constant)) - Expr = ch_expr.Expr; - else if ((ec_expr != null) && (ec_expr.Child is Constant)) - Expr = ec_expr.Child; - else if (Expr is ArrayCreation) { - ArrayCreation ac = (ArrayCreation) Expr; - - Expr = ac.TurnIntoConstant (); - if (Expr == null){ - Report.Error (150, Location, "A constant value is expected"); - value = null; - return false; - } - } else { - if (errors == Report.Errors) - Report.Error (150, Location, "A constant value is expected"); - value = null; - return false; - } - - ce = Expr as Constant; - } + return true; + } - if (type != real_expr.Type) { - ce = ChangeType (Location, ce, type); - if (ce == null){ - value = null; - return false; - } - Expr = ce; - } - ConstantValue = ce.GetValue (); - - if (type.IsEnum){ - // - // This sadly does not work for our user-defined enumerations types ;-( - // - try { - ConstantValue = System.Enum.ToObject ( - type, ConstantValue); - } catch (ArgumentException){ - Report.Error ( - -16, Location, - ".NET SDK 1.0 does not permit to create the constant "+ - " field from a user-defined enumeration"); - } + public Constant Value { + get { + return value; } + } - FieldBuilder.SetConstant (ConstantValue); + #endregion + } - if (!TypeManager.RegisterFieldValue (FieldBuilder, ConstantValue)) - throw new Exception ("Cannot register const value"); + public class ExternalConstant : IConstant + { + FieldInfo fi; + Constant value; - value = ConstantValue; - resolved = true; - return true; + public ExternalConstant (FieldInfo fi) + { + this.fi = fi; } - - - /// - /// Emits the field value by evaluating the expression - /// - public override void Emit () + + private ExternalConstant (FieldInfo fi, Constant value): + this (fi) + { + this.value = value; + } + + // + // Decimal constants cannot be encoded in the constant blob, and thus are marked + // as IsInitOnly ('readonly' in C# parlance). We get its value from the + // DecimalConstantAttribute metadata. + // + public static IConstant CreateDecimal (FieldInfo fi) + { + if (fi is FieldBuilder) + return null; + + object[] attrs = fi.GetCustomAttributes (TypeManager.decimal_constant_attribute_type, false); + if (attrs.Length != 1) + return null; + + IConstant ic = new ExternalConstant (fi, + new DecimalConstant (((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value, Location.Null)); + + return ic; + } + + #region IConstant Members + + public void CheckObsoleteness (Location loc) { - object value; - LookupConstantValue (out value); + ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (fi); + if (oa == null) { + return; + } + + AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (fi), loc); + } - if (OptAttributes != null) { - OptAttributes.Emit (const_ec, this); + public bool ResolveValue () + { + if (value != null) + return true; + + if (fi.DeclaringType.IsEnum) { + value = Expression.Constantify (fi.GetValue (fi), TypeManager.EnumToUnderlying (fi.FieldType)); + value = new EnumConstant (value, fi.DeclaringType); + return true; } - base.Emit (); + value = Expression.Constantify (fi.GetValue (fi), fi.FieldType); + return true; } - } -} + public Constant Value { + get { + return value; + } + } + #endregion + } + +}