2009-01-02 Ivan N. Zlatev <contact@i-nz.net>
[mono.git] / mcs / mcs / const.cs
index 5da0b004f32c309b2eaff2478a3be1b2405b3bed..1f082adb94bee259b43431e0a123ac1446d66985 100644 (file)
@@ -5,8 +5,8 @@
 //   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 {
@@ -24,8 +24,9 @@ namespace Mono.CSharp {
        }
 
        public class Const : FieldBase, IConstant {
-               Constant value;
+               protected Constant value;
                bool in_transit;
+               bool resolved;
                bool define_called;
 
                public const int AllowedModifiers =
@@ -35,9 +36,9 @@ namespace Mono.CSharp {
                        Modifiers.INTERNAL |
                        Modifiers.PRIVATE;
 
-               public Const (DeclSpace parent, Expression constant_type, string name,
+               public Const (DeclSpace parent, FullNamedExpression type, string name,
                              Expression expr, int mod_flags, Attributes attrs, Location loc)
-                       : base (parent, constant_type, mod_flags, AllowedModifiers,
+                       : base (parent, type, mod_flags, AllowedModifiers,
                                new MemberName (name, loc), attrs)
                {
                        initializer = expr;
@@ -73,7 +74,6 @@ namespace Mono.CSharp {
                        Type ttype = MemberType;
                        if (!IsConstantTypeValid (ttype)) {
                                Error_InvalidConstantType (ttype, Location);
-                               return false;
                        }
 
                        // If the constant is private then we don't need any field the
@@ -81,9 +81,6 @@ namespace Mono.CSharp {
                        //if ((ModFlags & Modifiers.PRIVATE) != 0 && RootContext.Optimize)
                        //      return true;
 
-                       while (ttype.IsArray)
-                           ttype = TypeManager.GetElementType (ttype);
-
                        FieldAttributes field_attr = FieldAttributes.Static | Modifiers.FieldAttr (ModFlags);
                        // Decimals cannot be emitted into the constant blob.  So, convert to 'readonly'.
                        if (ttype == TypeManager.decimal_type) {
@@ -94,10 +91,11 @@ namespace Mono.CSharp {
 
                        FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType, field_attr);
                        TypeManager.RegisterConstant (FieldBuilder, this);
+                       Parent.MemberCache.AddMember (FieldBuilder, this);
 
-                       if (ttype == TypeManager.decimal_type)
+                       if ((field_attr & FieldAttributes.InitOnly) != 0)
                                Parent.PartialContainer.RegisterFieldForInitialization (this,
-                                       new FieldInitializer (FieldBuilder, initializer, Parent));
+                                       new FieldInitializer (FieldBuilder, initializer, this));
 
                        return true;
                }
@@ -128,19 +126,48 @@ namespace Mono.CSharp {
                                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{
+                               EmitDecimalConstant ();
+                       } else{
                                FieldBuilder.SetConstant (value.GetTypedValue ());
                        }
 
                        base.Emit ();
                }
 
+               void EmitDecimalConstant ()
+               {
+                       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;
+                       }
+
+                       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 (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);
@@ -152,10 +179,10 @@ namespace Mono.CSharp {
                                mc.GetSignatureForError ());
                }
 
-               public static void Error_ConstantCanBeInitializedWithNullOnly (Location loc, string name)
+               public static void Error_ConstantCanBeInitializedWithNullOnly (Type type, Location loc, string name)
                {
-                       Report.Error (134, loc, "`{0}': the constant of reference type other than string can only be initialized with null",
-                               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)
@@ -167,40 +194,48 @@ namespace Mono.CSharp {
 
                public bool ResolveValue ()
                {
-                       if (value != null)
-                               return true;
+                       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);
-                       value = initializer.ResolveAsConstant (ec, this);
+                       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;
+               }
 
+               protected virtual Constant DoResolveValue (EmitContext ec)
+               {
+                       Constant value = initializer.ResolveAsConstant (ec, this);
                        if (value == null)
-                               return false;
+                               return null;
 
-                       Constant c  = value.ConvertImplicitly (MemberType);
+                       Constant c = value.ConvertImplicitly (MemberType);
                        if (c == null) {
-                               if (!MemberType.IsValueType && MemberType != TypeManager.string_type && !value.IsDefaultValue)
-                                       Error_ConstantCanBeInitializedWithNullOnly (Location, GetSignatureForError ());
+                               if (TypeManager.IsReferenceType (MemberType))
+                                       Error_ConstantCanBeInitializedWithNullOnly (MemberType, Location, GetSignatureForError ());
                                else
-                                       value.Error_ValueCannotBeConverted (null, Location, MemberType, false);
-                               return false;
+                                       value.Error_ValueCannotBeConverted (ec, Location, MemberType, false);
                        }
 
-                       value = c;
-                       return true;
+                       return c;
                }
 
-               public Constant CreateConstantReference (Location loc)
+               public virtual Constant CreateConstantReference (Location loc)
                {
                        if (value == null)
                                return null;
@@ -236,7 +271,10 @@ namespace Mono.CSharp {
                {
                        if (fi is FieldBuilder)
                                return null;
-                       
+
+                       if (TypeManager.decimal_constant_attribute_type == null)
+                               return null;
+
                        object[] attrs = fi.GetCustomAttributes (TypeManager.decimal_constant_attribute_type, false);
                        if (attrs.Length != 1)
                                return null;
@@ -270,7 +308,7 @@ namespace Mono.CSharp {
 
                public Constant CreateConstantReference (Location loc)
                {
-                       return Constant.CreateConstant (fi.FieldType, value, loc);
+                       return Constant.CreateConstant (TypeManager.TypeToCoreType (fi.FieldType), value, loc);
                }
 
                #endregion