X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fconst.cs;h=6b502c04f2b2986eb189a973afd4b72362c157ae;hb=0a615a1dec61b88a58a956ded2d544e38548f016;hp=b947e4d68f5485ee6552e1e4abb33d32d71d8459;hpb=d49951ccf584ba637afb1dab7fff714478e3174d;p=mono.git diff --git a/mcs/mcs/const.cs b/mcs/mcs/const.cs index b947e4d68f5..6b502c04f2b 100644 --- a/mcs/mcs/const.cs +++ b/mcs/mcs/const.cs @@ -5,53 +5,36 @@ // 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; +using System.Reflection.Emit; - using System; - using System.Reflection; - using System.Reflection.Emit; - using System.Collections; +namespace Mono.CSharp { - public interface IConstant + public class Const : FieldBase { - void CheckObsoleteness (Location loc); - bool ResolveValue (); - Constant CreateConstantReference (Location loc); - } - - public class Const : FieldMember, IConstant { Constant value; - bool in_transit; - bool define_called; - public const int AllowedModifiers = + public const Modifiers AllowedModifiers = Modifiers.NEW | Modifiers.PUBLIC | Modifiers.PROTECTED | Modifiers.INTERNAL | Modifiers.PRIVATE; - 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, + public Const (DeclSpace parent, FullNamedExpression type, string name, + Expression expr, Modifiers mod_flags, Attributes attrs, Location loc) + : base (parent, type, mod_flags, AllowedModifiers, new MemberName (name, loc), attrs) { - initializer = expr; - ModFlags |= Modifiers.STATIC; - } + if (expr != null) + initializer = new ConstInitializer (this, expr); - protected override bool CheckBase () - { - // 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 (); + ModFlags |= Modifiers.STATIC; } /// @@ -59,54 +42,40 @@ namespace Mono.CSharp { /// 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; - Type ttype = MemberType; - if (!IsConstantTypeValid (ttype)) { - Error_InvalidConstantType (ttype, Location); - return false; + TypeSpec ttype = MemberType; + if (!ttype.IsConstantCompatible) { + Error_InvalidConstantType (ttype, Location, Report); } - while (ttype.IsArray) - ttype = TypeManager.GetElementType (ttype); - - FieldAttributes field_attr = FieldAttributes.Static | Modifiers.FieldAttr (ModFlags); + FieldAttributes field_attr = FieldAttributes.Static | ModifiersExtensions.FieldAttr (ModFlags); // Decimals cannot be emitted into the constant blob. So, convert to 'readonly'. if (ttype == TypeManager.decimal_type) { field_attr |= FieldAttributes.InitOnly; - Parent.PartialContainer.RegisterFieldForInitialization (this); } else { field_attr |= FieldAttributes.Literal; } - FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType, field_attr); + FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType.GetMetaInfo (), field_attr); + spec = new ConstSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags, initializer); - TypeManager.RegisterConstant (FieldBuilder, this); + Parent.MemberCache.AddMember (spec); + + if ((field_attr & FieldAttributes.InitOnly) != 0) + Parent.PartialContainer.RegisterFieldForInitialization (this, + new FieldInitializer (this, initializer, this)); return true; } - public static bool IsConstantTypeValid (Type t) + public Constant DefineValue () { - if (TypeManager.IsBuiltinOrEnum (t)) - return true; - - if (t.IsPointer || t.IsValueType) - return false; - - if (TypeManager.IsGenericParameter (t)) - return false; + if (value == null) + value = initializer.Resolve (new ResolveContext (this)) as Constant; - return true; + return value; } /// @@ -114,155 +83,140 @@ namespace Mono.CSharp { /// public override void Emit () { - 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.SetCustomAttribute (CreateDecimalConstantAttribute (value)); + } else{ FieldBuilder.SetConstant (value.GetTypedValue ()); } base.Emit (); } - public static void Error_ExpressionMustBeConstant (Location loc, string e_name) + public static CustomAttributeBuilder CreateDecimalConstantAttribute (Constant c) { - Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name); - } + PredefinedAttribute pa = PredefinedAttributes.Get.DecimalConstant; + if (pa.Constructor == null && + !pa.ResolveConstructor (c.Location, TypeManager.byte_type, TypeManager.byte_type, + TypeManager.uint32_type, TypeManager.uint32_type, TypeManager.uint32_type)) + return null; - 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 ()); - } + Decimal d = (Decimal) c.GetValue (); + 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] + }; - 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); + return new CustomAttributeBuilder (pa.Constructor, args); } - public static void Error_InvalidConstantType (Type t, Location loc) + public static void Error_InvalidConstantType (TypeSpec t, Location loc, Report Report) { - Report.Error (283, loc, "The type `{0}' cannot be declared const", TypeManager.CSharpName (t)); + if (t.IsGenericParameter) { + Report.Error (1959, loc, + "Type parameter `{0}' cannot be declared const", TypeManager.CSharpName (t)); + } else { + Report.Error (283, loc, + "The type `{0}' cannot be declared const", TypeManager.CSharpName (t)); + } } + } - #region IConstant Members + public class ConstSpec : FieldSpec + { + Expression value; - public bool ResolveValue () + public ConstSpec (TypeSpec declaringType, IMemberDefinition definition, TypeSpec memberType, FieldInfo fi, Modifiers mod, Expression value) + : base (declaringType, definition, memberType, fi, mod) { - if (value != null) - return true; + this.value = value; + } - SetMemberIsUsed (); - if (in_transit) { - Error_CyclicDeclaration (this); - // Suppress cyclic errors - value = New.Constantify (MemberType); - return false; + public Expression Value { + get { + return value; } - - in_transit = true; - // TODO: IResolveContext here - EmitContext ec = new EmitContext (this, Parent, Location, null, MemberType, ModFlags); - value = initializer.ResolveAsConstant (ec, this); - in_transit = false; - - if (value == null) - return false; - - value = value.ImplicitConversionRequired (MemberType, Location); - if (value == null) - return false; - - if (!MemberType.IsValueType && MemberType != TypeManager.string_type && !value.IsDefaultValue) { - Error_ConstantCanBeInitializedWithNullOnly (Location, GetSignatureForError ()); - return false; + private set { + this.value = value; } - - return true; - } - - public Constant CreateConstantReference (Location loc) - { - if (value == null) - return null; - - return Constant.CreateConstant (value.Type, value.GetValue(), loc); } - - #endregion } - public class ExternalConstant : IConstant + class ConstInitializer : ShimExpression { - FieldInfo fi; - object value; + bool in_transit; + protected readonly FieldBase field; - public ExternalConstant (FieldInfo fi) + public ConstInitializer (FieldBase field, Expression value) + : base (value) { - this.fi = fi; - } + if (value != null) + this.loc = value.Location; - private ExternalConstant (FieldInfo fi, object value): - this (fi) - { - this.value = value; + this.field = field; } - // - // 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) + protected override Expression DoResolve (ResolveContext unused) { - if (fi is FieldBuilder) - return null; - - object[] attrs = fi.GetCustomAttributes (TypeManager.decimal_constant_attribute_type, false); - if (attrs.Length != 1) - return null; + if (type != null) + return expr; - IConstant ic = new ExternalConstant (fi, - ((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value); + var opt = ResolveContext.Options.ConstantScope; + if (field is EnumMember) + opt |= ResolveContext.Options.EnumScope; - return ic; - } + // + // Use a context in which the constant was declared and + // not the one in which is referenced + // + var rc = new ResolveContext (field, opt); + expr = DoResolveInitializer (rc); + type = expr.Type; - #region IConstant Members + return expr; + } - public void CheckObsoleteness (Location loc) + protected virtual Expression DoResolveInitializer (ResolveContext rc) { - ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (fi); - if (oa == null) { - return; + if (in_transit) { + field.Compiler.Report.Error (110, field.Location, + "The evaluation of the constant value for `{0}' involves a circular definition", + field.GetSignatureForError ()); + + expr = null; + } else { + in_transit = true; + expr = expr.Resolve (rc); } - AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (fi), loc); - } + in_transit = false; - public bool ResolveValue () - { - if (value != null) - return true; + if (expr != null) { + Constant c = expr as Constant; + if (c != null) + c = field.ConvertInitializer (rc, c); + + if (c == null) { + if (TypeManager.IsReferenceType (field.MemberType)) + Error_ConstantCanBeInitializedWithNullOnly (rc, field.MemberType, loc, field.GetSignatureForError ()); + else if (!(expr is Constant)) + Error_ExpressionMustBeConstant (rc, field.Location, field.GetSignatureForError ()); + else + expr.Error_ValueCannotBeConverted (rc, loc, field.MemberType, false); + } + + expr = c; + } - value = fi.GetValue (fi); - return true; - } + if (expr == null) { + expr = New.Constantify (field.MemberType); + if (expr == null) + expr = Constant.CreateConstantFromValue (field.MemberType, null, Location); + expr = expr.Resolve (rc); + } - public Constant CreateConstantReference (Location loc) - { - return Constant.CreateConstant (fi.FieldType, value, loc); + return expr; } - - #endregion } - }