X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fconst.cs;h=3ad88788a7c16bf5800fa0f0a15d556287ea2b46;hb=d480bc52c57fcf5db8c86b09ed68a0dab1c10ffa;hp=1f082adb94bee259b43431e0a123ac1446d66985;hpb=3331634f37c395ea87d15a2f3338b2bc66a8470a;p=mono.git diff --git a/mcs/mcs/const.cs b/mcs/mcs/const.cs index 1f082adb94b..3ad88788a7c 100644 --- a/mcs/mcs/const.cs +++ b/mcs/mcs/const.cs @@ -9,109 +9,74 @@ // 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; - - public const int AllowedModifiers = + public const Modifiers AllowedModifiers = Modifiers.NEW | Modifiers.PUBLIC | Modifiers.PROTECTED | Modifiers.INTERNAL | Modifiers.PRIVATE; - public Const (DeclSpace parent, FullNamedExpression type, string name, - Expression expr, int mod_flags, Attributes attrs, Location loc) - : base (parent, 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); + if (!member_type.IsConstantCompatible) { + Error_InvalidConstantType (member_type, 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) { + if (member_type == TypeManager.decimal_type) { field_attr |= FieldAttributes.InitOnly; } else { 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 (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); } /// @@ -119,44 +84,25 @@ namespace Mono.CSharp { /// public override void Emit () { - if (!ResolveValue ()) - return; - - if (FieldBuilder == null) - return; - - if (value.Type == TypeManager.decimal_type) { - EmitDecimalConstant (); - } 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 (); } - void EmitDecimalConstant () + public static CustomAttributeBuilder CreateDecimalConstantAttribute (Constant c) { - ConstructorInfo ctor = TypeManager.decimal_constant_attribute_ctor; - if (ctor == null) { - if (TypeManager.decimal_constant_attribute_type == null) { - TypeManager.decimal_constant_attribute_type = TypeManager.CoreLookupType ( - "System.Runtime.CompilerServices", "DecimalConstantAttribute", Kind.Class, true); - - if (TypeManager.decimal_constant_attribute_type == null) - return; - } - - ctor = TypeManager.GetPredefinedConstructor (TypeManager.decimal_constant_attribute_type, Location, - TypeManager.byte_type, TypeManager.byte_type, - TypeManager.uint32_type, TypeManager.uint32_type, TypeManager.uint32_type); - - if (ctor == null) - return; - - TypeManager.decimal_constant_attribute_ctor = ctor; - } + 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; - Decimal d = ((DecimalConstant) value).Value; + Decimal d = (Decimal) c.GetValue (); int [] bits = Decimal.GetBits (d); object [] args = new object [] { (byte) (bits [3] >> 16), @@ -164,154 +110,135 @@ namespace Mono.CSharp { (uint) bits [2], (uint) bits [1], (uint) bits [0] }; - CustomAttributeBuilder cab = new CustomAttributeBuilder (ctor, args); - FieldBuilder.SetCustomAttribute (cab); - } - - 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); + return new CustomAttributeBuilder (pa.Constructor, args); } - public static void Error_CyclicDeclaration (MemberCore mc) + public static void Error_InvalidConstantType (TypeSpec t, Location loc, Report Report) { - 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) - { - 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) - { - 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 (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; - // TODO: IResolveContext here - EmitContext ec = new EmitContext ( - this, Parent, Location, null, MemberType, ModFlags); - ec.InEnumContext = this is EnumMember; - ec.IsAnonymousMethodAllowed = false; - value = DoResolveValue (ec); - in_transit = false; - resolved = true; - return value != null; + this.value = value; } - protected virtual Constant DoResolveValue (EmitContext 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); + // + // This expresion is guarantee to be a constant at emit phase only + // + public Expression Value { + get { + return value; } - - return c; } - public virtual Constant CreateConstantReference (Location loc) + // + // 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 == null) - return null; + if (value.eclass != ExprClass.Value) + value = value.Resolve (rc); - return Constant.CreateConstant (value.Type, value.GetValue(), loc); + return (Constant) value; } - - #endregion } - public class ExternalConstant : IConstant + public class ConstInitializer : ShimExpression { - FieldInfo fi; - object 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, object 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; - - if (TypeManager.decimal_constant_attribute_type == null) - return null; + if (type != null) + return expr; - object[] attrs = fi.GetCustomAttributes (TypeManager.decimal_constant_attribute_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, 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); + } - value = fi.GetValue (fi); - return true; + expr = c; + } + + if (expr == null) { + expr = New.Constantify (field.MemberType); + if (expr == null) + expr = Constant.CreateConstantFromValue (field.MemberType, null, Location); + expr = expr.Resolve (rc); + } + + return expr; } - public Constant CreateConstantReference (Location loc) + public override string GetSignatureForError () { - return Constant.CreateConstant (TypeManager.TypeToCoreType (fi.FieldType), value, loc); - } + if (Name == null) + return field.GetSignatureForError (); - #endregion + return field.Parent.GetSignatureForError () + "." + Name; + } } - }