X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fconst.cs;h=3ad88788a7c16bf5800fa0f0a15d556287ea2b46;hb=d480bc52c57fcf5db8c86b09ed68a0dab1c10ffa;hp=7422b492b3f23be40c2771edca882855dc315718;hpb=987f8c63e214937c50dcb308149f7558a2cbba41;p=mono.git diff --git a/mcs/mcs/const.cs b/mcs/mcs/const.cs index 7422b492b3f..3ad88788a7c 100644 --- a/mcs/mcs/const.cs +++ b/mcs/mcs/const.cs @@ -5,108 +5,78 @@ // 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 Value { get; } - } - - 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, - new MemberName (name, loc), attrs) + public Const (DeclSpace parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs) + : base (parent, type, mod_flags, AllowedModifiers, name, attrs) { - initializer = expr; ModFlags |= Modifiers.STATIC; } - 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 (); - } - /// /// 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; - Type ttype = MemberType; - if (!IsConstantTypeValid (ttype)) { - Error_InvalidConstantType (ttype, Location); - return false; + if (!member_type.IsConstantCompatible) { + Error_InvalidConstantType (member_type, 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) { + if (member_type == 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); + + Parent.MemberCache.AddMember (spec); - TypeManager.RegisterConstant (FieldBuilder, this); + if ((field_attr & FieldAttributes.InitOnly) != 0) + Parent.PartialContainer.RegisterFieldForInitialization (this, + new FieldInitializer (spec, initializer, this)); + + if (declarators != null) { + var t = new TypeExpression (MemberType, TypeExpression.Location); + int index = Parent.PartialContainer.Constants.IndexOf (this); + foreach (var d in declarators) { + var c = new Const (Parent, t, ModFlags & ~Modifiers.STATIC, new MemberName (d.Name.Value, d.Name.Location), OptAttributes); + c.initializer = d.Initializer; + ((ConstInitializer) c.initializer).Name = d.Name.Value; + Parent.PartialContainer.Constants.Insert (++index, c); + } + } return true; } - public static bool IsConstantTypeValid (Type t) + public void DefineValue () { - if (TypeManager.IsBuiltinOrEnum (t)) - return true; - - if (t.IsPointer || t.IsValueType) - return false; - - if (TypeManager.IsGenericParameter (t)) - return false; - - return true; + var rc = new ResolveContext (this); + ((ConstSpec) spec).GetConstant (rc); } /// @@ -114,160 +84,161 @@ 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.SetConstant (value.GetTypedValue ()); + var c = ((ConstSpec) spec).Value as Constant; + if (c.Type == TypeManager.decimal_type) { + FieldBuilder.SetCustomAttribute (CreateDecimalConstantAttribute (c)); + } else { + FieldBuilder.SetConstant (c.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; - - SetMemberIsUsed (); - if (in_transit) { - Error_CyclicDeclaration (this); - // Suppress cyclic errors - value = New.Constantify (MemberType); - return false; - } - - 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; - } - - return true; + this.value = value; } - public Constant Value { + // + // This expresion is guarantee to be a constant at emit phase only + // + public Expression Value { get { return value; } } - #endregion + // + // For compiled constants we have to resolve the value as there could be constant dependecies. This + // is needed for imported constants too to get the right context type + // + public Constant GetConstant (ResolveContext rc) + { + if (value.eclass != ExprClass.Value) + value = value.Resolve (rc); + + return (Constant) value; + } } - public class ExternalConstant : IConstant + public class ConstInitializer : ShimExpression { - FieldInfo fi; - Constant value; + bool in_transit; + readonly FieldBase field; - public ExternalConstant (FieldInfo fi) + public ConstInitializer (FieldBase field, Expression value, Location loc) + : base (value) { - this.fi = fi; + this.loc = loc; + this.field = field; } - private ExternalConstant (FieldInfo fi, Constant value): - this (fi) - { - this.value = value; - } + public string Name { get; set; } - // - // 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, - new DecimalConstant (((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value, Location.Null)); + 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, expr.Location, + "The evaluation of the constant value for `{0}' involves a circular definition", + 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, expr.Location, GetSignatureForError ()); + else if (!(expr is Constant)) + Error_ExpressionMustBeConstant (rc, expr.Location, GetSignatureForError ()); + else + expr.Error_ValueCannotBeConverted (rc, expr.Location, field.MemberType, false); + } + + expr = c; + } - if (fi.DeclaringType.IsEnum) { - value = Expression.Constantify (fi.GetValue (fi), TypeManager.EnumToUnderlying (fi.FieldType)); - value = new EnumConstant (value, fi.DeclaringType); - return true; + if (expr == null) { + expr = New.Constantify (field.MemberType); + if (expr == null) + expr = Constant.CreateConstantFromValue (field.MemberType, null, Location); + expr = expr.Resolve (rc); } - value = Expression.Constantify (fi.GetValue (fi), fi.FieldType); - return true; + return expr; } - public Constant Value { - get { - return value; - } - } + public override string GetSignatureForError () + { + if (Name == null) + return field.GetSignatureForError (); - #endregion + return field.Parent.GetSignatureForError () + "." + Name; + } } - }