typing too much today
[mono.git] / mcs / mcs / const.cs
index 673554cf15654308f5e0ec76f41856b01bba693d..3ad88788a7c16bf5800fa0f0a15d556287ea2b46 100644 (file)
@@ -17,8 +17,6 @@ namespace Mono.CSharp {
 
        public class Const : FieldBase
        {
-               bool define_called;
-
                public const Modifiers AllowedModifiers =
                        Modifiers.NEW |
                        Modifiers.PUBLIC |
@@ -26,78 +24,59 @@ namespace Mono.CSharp {
                        Modifiers.INTERNAL |
                        Modifiers.PRIVATE;
 
-               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)
+               public Const (DeclSpace parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs)
+                       : base (parent, type, mod_flags, AllowedModifiers, name, attrs)
                {
-                       if (expr != null)
-                               initializer = new ConstInitializer (this, 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 ();
-               }
-
                /// <summary>
                ///   Defines the constant in the @parent
                /// </summary>
                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, Report);
+                       if (!member_type.IsConstantCompatible) {
+                               Error_InvalidConstantType (member_type, Location, Report);
                        }
 
                        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);
-                       spec = new ConstSpec (this, FieldBuilder, ModFlags, initializer);
+                       FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType.GetMetaInfo (), field_attr);
+                       spec = new ConstSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags, initializer);
 
-                       TypeManager.RegisterConstant (FieldBuilder, (ConstSpec) spec);
-                       Parent.MemberCache.AddMember (FieldBuilder, this);
+                       Parent.MemberCache.AddMember (spec);
 
                        if ((field_attr & FieldAttributes.InitOnly) != 0)
                                Parent.PartialContainer.RegisterFieldForInitialization (this,
-                                       new FieldInitializer (this, 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 (TypeManager.IsGenericParameter (t) || t.IsPointer)
-                               return false;
-
-                       return TypeManager.IsReferenceType (t);
+                       var rc = new ResolveContext (this);
+                       ((ConstSpec) spec).GetConstant (rc);
                }
 
                /// <summary>
@@ -105,14 +84,11 @@ namespace Mono.CSharp {
                /// </summary>
                public override void Emit ()
                {
-                       var value = initializer.Resolve (new ResolveContext (this)) as Constant;
-                       if (value == null || FieldBuilder == null)
-                               return;
-
-                       if (value.Type == TypeManager.decimal_type) {
-                               FieldBuilder.SetCustomAttribute (CreateDecimalConstantAttribute (value));
-                       } 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 ();
@@ -137,9 +113,9 @@ namespace Mono.CSharp {
                        return new CustomAttributeBuilder (pa.Constructor, args);
                }
 
-               public static void Error_InvalidConstantType (Type t, Location loc, Report Report)
+               public static void Error_InvalidConstantType (TypeSpec t, Location loc, Report Report)
                {
-                       if (TypeManager.IsGenericParameter (t)) {
+                       if (t.IsGenericParameter) {
                                Report.Error (1959, loc,
                                        "Type parameter `{0}' cannot be declared const", TypeManager.CSharpName (t));
                        } else {
@@ -153,36 +129,48 @@ namespace Mono.CSharp {
        {
                Expression value;
 
-               public ConstSpec (IMemberDefinition definition, FieldInfo fi, Modifiers mod, Expression value)
-                       : base (definition, fi, mod)
+               public ConstSpec (TypeSpec declaringType, IMemberDefinition definition, TypeSpec memberType, FieldInfo fi, Modifiers mod, Expression value)
+                       : base (declaringType, definition, memberType, fi, mod)
                {
                        this.value = value;
                }
 
+               //
+               // This expresion is guarantee to be a constant at emit phase only
+               //
                public Expression Value {
                        get {
                                return value;
                        }
-                       set {
-                               this.value = value;
-                       }
+               }
+
+               //
+               // 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;
                }
        }
 
-       class ConstInitializer : ShimExpression
+       public class ConstInitializer : ShimExpression
        {
                bool in_transit;
-               protected readonly FieldBase field;
+               readonly FieldBase field;
 
-               public ConstInitializer (FieldBase field, Expression value)
+               public ConstInitializer (FieldBase field, Expression value, Location loc)
                        : base (value)
                {
-                       if (value != null)
-                               this.loc = value.Location;
-
+                       this.loc = loc;
                        this.field = field;
                }
 
+               public string Name { get; set; }
+
                protected override Expression DoResolve (ResolveContext unused)
                {
                        if (type != null)
@@ -206,9 +194,9 @@ namespace Mono.CSharp {
                protected virtual Expression DoResolveInitializer (ResolveContext rc)
                {
                        if (in_transit) {
-                               field.Compiler.Report.Error (110, field.Location,
+                               field.Compiler.Report.Error (110, expr.Location,
                                        "The evaluation of the constant value for `{0}' involves a circular definition",
-                                       field.GetSignatureForError ());
+                                       GetSignatureForError ());
 
                                expr = null;
                        } else {
@@ -225,11 +213,11 @@ namespace Mono.CSharp {
 
                                if (c == null) {
                                        if (TypeManager.IsReferenceType (field.MemberType))
-                                               Error_ConstantCanBeInitializedWithNullOnly (rc, field.MemberType, loc, field.GetSignatureForError ());
+                                               Error_ConstantCanBeInitializedWithNullOnly (rc, field.MemberType, expr.Location, GetSignatureForError ());
                                        else if (!(expr is Constant))
-                                               Error_ExpressionMustBeConstant (rc, field.Location, field.GetSignatureForError ());
+                                               Error_ExpressionMustBeConstant (rc, expr.Location, GetSignatureForError ());
                                        else
-                                               expr.Error_ValueCannotBeConverted (rc, loc, field.MemberType, false);
+                                               expr.Error_ValueCannotBeConverted (rc, expr.Location, field.MemberType, false);
                                }
 
                                expr = c;
@@ -242,8 +230,15 @@ namespace Mono.CSharp {
                                expr = expr.Resolve (rc);
                        }
 
-
                        return expr;
                }
+
+               public override string GetSignatureForError ()
+               {
+                       if (Name == null)
+                               return field.GetSignatureForError ();
+
+                       return field.Parent.GetSignatureForError () + "." + Name;
+               }
        }
 }