2007-01-10 Chris Toshok <toshok@ximian.com>
[mono.git] / mcs / mcs / const.cs
index 3282d6f24bf7ac4517b973687025af49294a0da7..b947e4d68f5485ee6552e1e4abb33d32d71d8459 100644 (file)
@@ -20,12 +20,13 @@ namespace Mono.CSharp {
        {
                void CheckObsoleteness (Location loc);
                bool ResolveValue ();
-               Constant Value { get; }
+               Constant CreateConstantReference (Location loc);
        }
 
        public class Const : FieldMember, IConstant {
                Constant value;
                bool in_transit;
+               bool define_called;
 
                public const int AllowedModifiers =
                        Modifiers.NEW |
@@ -48,7 +49,7 @@ namespace Mono.CSharp {
                        // 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 (ParentContainer.BaseCache == null)
+                       if (Parent.PartialContainer.BaseCache == null)
                                return true;
                        return base.CheckBase ();
                }
@@ -58,14 +59,23 @@ namespace Mono.CSharp {
                /// </summary>
                public override bool Define ()
                {
-                       // Make Define () idempotent, but ensure that the error check happens.
-                       if (FieldBuilder != null)
-                               return base.CheckBase ();
+                       // 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;
+                       }
+
                        while (ttype.IsArray)
                            ttype = TypeManager.GetElementType (ttype);
 
@@ -73,9 +83,8 @@ namespace Mono.CSharp {
                        // Decimals cannot be emitted into the constant blob.  So, convert to 'readonly'.
                        if (ttype == TypeManager.decimal_type) {
                                field_attr |= FieldAttributes.InitOnly;
-                               ParentContainer.RegisterFieldForInitialization (this);
-                       }
-                       else {
+                               Parent.PartialContainer.RegisterFieldForInitialization (this);
+                       } else {
                                field_attr |= FieldAttributes.Literal;
                        }
 
@@ -85,7 +94,21 @@ namespace Mono.CSharp {
 
                        return true;
                }
-               
+
+               public static bool IsConstantTypeValid (Type t)
+               {
+                       if (TypeManager.IsBuiltinOrEnum (t))
+                               return true;
+
+                       if (t.IsPointer || t.IsValueType)
+                               return false;
+                       
+                       if (TypeManager.IsGenericParameter (t))
+                               return false;
+
+                       return true;
+               }
+
                /// <summary>
                ///  Emits the field value by evaluating the expression
                /// </summary>
@@ -108,13 +131,8 @@ namespace Mono.CSharp {
                        base.Emit ();
                }
 
-               public static void Error_ExpressionMustBeConstant (Type constantType, Location loc, string e_name)
+               public static void Error_ExpressionMustBeConstant (Location loc, string e_name)
                {
-                       if (constantType != null && TypeManager.IsValueType (constantType) &&
-                               !TypeManager.IsBuiltinOrEnum (constantType)) {
-                               Report.Error (283, loc, "The type `{0}' cannot be declared const", TypeManager.CSharpName (constantType));
-                               return;
-                       }
                        Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
                }
 
@@ -130,6 +148,11 @@ namespace Mono.CSharp {
                                name);
                }
 
+               public static void Error_InvalidConstantType (Type t, Location loc)
+               {
+                       Report.Error (283, loc, "The type `{0}' cannot be declared const", TypeManager.CSharpName (t));
+               }
+
                #region IConstant Members
 
                public bool ResolveValue ()
@@ -154,7 +177,7 @@ namespace Mono.CSharp {
                        if (value == null)
                                return false;
 
-                       value = value.ToType (MemberType, Location);
+                       value = value.ImplicitConversionRequired (MemberType, Location);
                        if (value == null)
                                return false;
 
@@ -166,10 +189,12 @@ namespace Mono.CSharp {
                        return true;
                }
 
-               public Constant Value {
-                       get {
-                               return value;
-                       }
+               public Constant CreateConstantReference (Location loc)
+               {
+                       if (value == null)
+                               return null;
+
+                       return Constant.CreateConstant (value.Type, value.GetValue(), loc);
                }
 
                #endregion
@@ -178,14 +203,14 @@ namespace Mono.CSharp {
        public class ExternalConstant : IConstant
        {
                FieldInfo fi;
-               Constant value;
+               object value;
 
                public ExternalConstant (FieldInfo fi)
                {
                        this.fi = fi;
                }
 
-               private ExternalConstant (FieldInfo fi, Constant value):
+               private ExternalConstant (FieldInfo fi, object value):
                        this (fi)
                {
                        this.value = value;
@@ -206,7 +231,7 @@ namespace Mono.CSharp {
                                return null;
 
                        IConstant ic = new ExternalConstant (fi,
-                               new DecimalConstant (((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value, Location.Null));
+                               ((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value);
 
                        return ic;
                }
@@ -228,20 +253,13 @@ namespace Mono.CSharp {
                        if (value != null)
                                return true;
 
-                       if (fi.DeclaringType.IsEnum) {
-                               value = Expression.Constantify (fi.GetValue (fi), TypeManager.EnumToUnderlying (fi.FieldType));
-                               value = new EnumConstant (value, fi.DeclaringType);
-                               return true;
-                       }
-
-                       value = Expression.Constantify (fi.GetValue (fi), fi.FieldType);
+                       value = fi.GetValue (fi);
                        return true;
                }
 
-               public Constant Value {
-                       get {
-                               return value;
-                       }
+               public Constant CreateConstantReference (Location loc)
+               {
+                       return Constant.CreateConstant (fi.FieldType, value, loc);
                }
 
                #endregion