X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fconst.cs;h=6b502c04f2b2986eb189a973afd4b72362c157ae;hb=0a615a1dec61b88a58a956ded2d544e38548f016;hp=c720d808e68f0ad514c8eb07a429954c98566058;hpb=2332d6ff00c77598def60262d6c620b4e340db9c;p=mono.git diff --git a/mcs/mcs/const.cs b/mcs/mcs/const.cs index c720d808e68..6b502c04f2b 100644 --- a/mcs/mcs/const.cs +++ b/mcs/mcs/const.cs @@ -9,27 +9,17 @@ // 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 : FieldBase, IConstant { - protected Constant value; - bool in_transit; - bool resolved; - bool define_called; + Constant value; - public const int AllowedModifiers = + public const Modifiers AllowedModifiers = Modifiers.NEW | Modifiers.PUBLIC | Modifiers.PROTECTED | @@ -37,22 +27,14 @@ namespace Mono.CSharp { Modifiers.PRIVATE; public Const (DeclSpace parent, FullNamedExpression type, string name, - Expression expr, int mod_flags, Attributes attrs, Location loc) + 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; } /// @@ -60,28 +42,15 @@ 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); + TypeSpec ttype = MemberType; + if (!ttype.IsConstantCompatible) { + Error_InvalidConstantType (ttype, Location, Report); } - // If the constant is private then we don't need any field the - // value is already inlined and cannot be referenced - //if ((ModFlags & Modifiers.PRIVATE) != 0 && RootContext.Optimize) - // return true; - - 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; @@ -89,26 +58,24 @@ namespace Mono.CSharp { field_attr |= FieldAttributes.Literal; } - FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType, field_attr); - TypeManager.RegisterConstant (FieldBuilder, this); - Parent.MemberCache.AddMember (FieldBuilder, this); + FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType.GetMetaInfo (), field_attr); + spec = new ConstSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags, initializer); + + Parent.MemberCache.AddMember (spec); if ((field_attr & FieldAttributes.InitOnly) != 0) Parent.PartialContainer.RegisterFieldForInitialization (this, - new FieldInitializer (FieldBuilder, initializer, this)); + new FieldInitializer (this, initializer, this)); return true; } - public static bool IsConstantTypeValid (Type t) + public Constant DefineValue () { - if (TypeManager.IsBuiltinOrEnum (t)) - return true; - - if (TypeManager.IsGenericParameter (t) || t.IsPointer) - return false; + if (value == null) + value = initializer.Resolve (new ResolveContext (this)) as Constant; - return TypeManager.IsReferenceType (t); + return value; } /// @@ -116,12 +83,6 @@ namespace Mono.CSharp { /// public override void Emit () { - if (!ResolveValue ()) - return; - - if (FieldBuilder == null) - return; - if (value.Type == TypeManager.decimal_type) { FieldBuilder.SetCustomAttribute (CreateDecimalConstantAttribute (value)); } else{ @@ -150,26 +111,9 @@ namespace Mono.CSharp { return new CustomAttributeBuilder (pa.Constructor, args); } - 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 (Type type, Location loc, string name) + public static void Error_InvalidConstantType (TypeSpec t, Location loc, Report Report) { - Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null", - name, TypeManager.CSharpName (type)); - } - - public static void Error_InvalidConstantType (Type t, Location loc) - { - if (TypeManager.IsGenericParameter (t)) { + if (t.IsGenericParameter) { Report.Error (1959, loc, "Type parameter `{0}' cannot be declared const", TypeManager.CSharpName (t)); } else { @@ -177,132 +121,102 @@ namespace Mono.CSharp { "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 (resolved) - return value != null; - - SetMemberIsUsed (); - if (in_transit) { - Error_CyclicDeclaration (this); - // Suppress cyclic errors - value = New.Constantify (MemberType); - resolved = true; - return false; - } - - in_transit = true; - - ResolveContext.Options opt = ResolveContext.Options.ConstantScope; - if (this is EnumMember) - opt |= ResolveContext.Options.EnumScope; - - ResolveContext rc = new ResolveContext (this, opt); - value = DoResolveValue (rc); - - in_transit = false; - resolved = true; - return value != null; + this.value = value; } - protected virtual Constant DoResolveValue (ResolveContext ec) - { - Constant value = initializer.ResolveAsConstant (ec, this); - if (value == null) - return null; - - Constant c = value.ConvertImplicitly (MemberType); - if (c == null) { - if (TypeManager.IsReferenceType (MemberType)) - Error_ConstantCanBeInitializedWithNullOnly (MemberType, Location, GetSignatureForError ()); - else - value.Error_ValueCannotBeConverted (ec, Location, MemberType, false); + public Expression Value { + get { + return value; + } + private set { + this.value = value; } - - return c; - } - - public virtual 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; + if (type != null) + return expr; - PredefinedAttribute pa = PredefinedAttributes.Get.DecimalConstant; - if (!pa.IsDefined) - return null; - - object[] attrs = fi.GetCustomAttributes (pa.Type, false); - if (attrs.Length != 1) - return null; + var opt = ResolveContext.Options.ConstantScope; + if (field is EnumMember) + opt |= ResolveContext.Options.EnumScope; - IConstant ic = new ExternalConstant (fi, - ((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value); + // + // 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; - return ic; + return expr; } - #region IConstant Members - - 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 (TypeManager.TypeToCoreType (fi.FieldType), value, loc); + return expr; } - - #endregion } - }