X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fconst.cs;h=b947e4d68f5485ee6552e1e4abb33d32d71d8459;hb=43b6678d45b2cf3705971998e1f04f67ef4d7667;hp=1c15f85ecaa87a95376b2a3753923b132a7a94c5;hpb=812e471a9fa329c17bb3bb52a977c72e6a447366;p=mono.git diff --git a/mcs/mcs/const.cs b/mcs/mcs/const.cs index 1c15f85ecaa..b947e4d68f5 100644 --- a/mcs/mcs/const.cs +++ b/mcs/mcs/const.cs @@ -9,15 +9,6 @@ // // -// -// 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; @@ -25,14 +16,17 @@ namespace Mono.CSharp { using System.Reflection.Emit; using System.Collections; - public class Const : FieldMember { - public Expression Expr; - EmitContext const_ec; - - bool resolved = false; - object ConstantValue = null; + public interface IConstant + { + void CheckObsoleteness (Location loc); + bool ResolveValue (); + Constant CreateConstantReference (Location loc); + } - bool in_transit = false; + public class Const : FieldMember, IConstant { + Constant value; + bool in_transit; + bool define_called; public const int AllowedModifiers = Modifiers.NEW | @@ -41,54 +35,56 @@ 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, - new MemberName (name), null, attrs, loc) + new MemberName (name, loc), attrs) { - Expr = expr; + initializer = expr; ModFlags |= Modifiers.STATIC; } -#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 (Parent.PartialContainer.BaseCache == null) + return true; + return base.CheckBase (); } -#endif /// /// Defines the constant in the @parent /// public override bool Define () { + // Because constant define can be called from other class + if (define_called) { + CheckBase (); + return FieldBuilder != null; + } + + define_called = true; + if (!base.Define ()) return false; - const_ec = new EmitContext (Parent, Location, null, MemberType, ModFlags); - Type ttype = MemberType; - while (ttype.IsArray) - ttype = TypeManager.GetElementType (ttype); - - if (!TypeManager.IsBuiltinType(ttype) && (!ttype.IsSubclassOf(TypeManager.enum_type)) && !(Expr is NullLiteral)){ - Report.Error ( - -3, Location, - "Constant type is not valid (only system types are allowed)"); + if (!IsConstantTypeValid (ttype)) { + Error_InvalidConstantType (ttype, Location); return false; } + while (ttype.IsArray) + ttype = TypeManager.GetElementType (ttype); + FieldAttributes field_attr = FieldAttributes.Static | Modifiers.FieldAttr (ModFlags); - // I don't know why but they emit decimal constant as InitOnly + // Decimals cannot be emitted into the constant blob. So, convert to 'readonly'. if (ttype == TypeManager.decimal_type) { field_attr |= FieldAttributes.InitOnly; - } - else { + Parent.PartialContainer.RegisterFieldForInitialization (this); + } else { field_attr |= FieldAttributes.Literal; } @@ -99,207 +95,174 @@ namespace Mono.CSharp { 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) + public static bool IsConstantTypeValid (Type t) { - if (type == TypeManager.object_type) - return expr; + if (TypeManager.IsBuiltinOrEnum (t)) + return true; - bool fail; + if (t.IsPointer || t.IsValueType) + return false; + + if (TypeManager.IsGenericParameter (t)) + return false; - // from the null type to any reference-type. - if (expr.Type == TypeManager.null_type && !type.IsValueType && !TypeManager.IsEnumType (type)) - return NullLiteral.Null; + return true; + } - if (!Convert.ImplicitStandardConversionExists (Convert.ConstantEC, expr, type)){ - Convert.Error_CannotImplicitConversion (loc, expr.Type, type); - return null; - } + /// + /// Emits the field value by evaluating the expression + /// + public override void Emit () + { + if (!ResolveValue ()) + return; - // Special-case: The 0 literal can be converted to an enum value, - // and ImplicitStandardConversionExists will return true in that case. - if (expr.Type == TypeManager.int32_type && TypeManager.IsEnumType (type)){ - if (expr is IntLiteral && ((IntLiteral) expr).Value == 0) - return new EnumConstant (expr, type); + 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); } - - 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)); + else{ + FieldBuilder.SetConstant (value.GetTypedValue ()); } - 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 if (type == TypeManager.decimal_type) - retval = new DecimalConstant ((decimal) constant_value); - else - throw new Exception ("LookupConstantValue: Unhandled constant type: " + type); - - return retval; + base.Emit (); } - - /// - /// 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) + + 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); + } + + 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 ()); + } + + 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); + } + + public static void Error_InvalidConstantType (Type t, Location loc) + { + Report.Error (283, loc, "The type `{0}' cannot be declared const", TypeManager.CSharpName (t)); + } + + #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.ImplicitConversionRequired (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){ - Report.Error (133, Location, "Arrays can not be constant"); - } 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 (MemberType != real_expr.Type) { - ce = ChangeType (Location, ce, MemberType); - if (ce == null){ - value = null; - return false; - } - Expr = ce; - } - ConstantValue = ce.GetValue (); - - if (MemberType.IsEnum){ - // - // This sadly does not work for our user-defined enumerations types ;-( - // - try { - ConstantValue = System.Enum.ToObject ( - MemberType, 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 CreateConstantReference (Location loc) + { + if (value == null) + return null; - if (ce is DecimalConstant) { - Decimal d = ((DecimalConstant)ce).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 (ConstantValue); - } + return Constant.CreateConstant (value.Type, value.GetValue(), loc); + } - if (!TypeManager.RegisterFieldValue (FieldBuilder, ConstantValue)) - throw new Exception ("Cannot register const value"); + #endregion + } - value = ConstantValue; - resolved = true; - return true; + public class ExternalConstant : IConstant + { + FieldInfo fi; + object value; + + public ExternalConstant (FieldInfo fi) + { + this.fi = fi; } - - - /// - /// Emits the field value by evaluating the expression - /// - public override void Emit () + + private ExternalConstant (FieldInfo fi, object value): + this (fi) { - object value; - LookupConstantValue (out value); + this.value = value; + } - if (OptAttributes != null) { - OptAttributes.Emit (const_ec, this); + // + // 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, + ((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value); + + return ic; + } + + #region IConstant Members + + public void CheckObsoleteness (Location loc) + { + ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (fi); + if (oa == null) { + return; } - base.Emit (); + AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (fi), loc); + } + + public bool ResolveValue () + { + if (value != null) + return true; + + value = fi.GetValue (fi); + return true; } - } -} + public Constant CreateConstantReference (Location loc) + { + return Constant.CreateConstant (fi.FieldType, value, loc); + } + #endregion + } + +}