2 // const.cs: Constant declarations.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // (C) 2001 Ximian, Inc.
12 namespace Mono.CSharp {
15 using System.Reflection;
16 using System.Reflection.Emit;
17 using System.Collections;
19 public interface IConstant
21 void CheckObsoleteness (Location loc);
23 Constant CreateConstantReference (Location loc);
26 public class Const : FieldBase, IConstant {
31 public const int AllowedModifiers =
38 public Const (DeclSpace parent, Expression constant_type, string name,
39 Expression expr, int mod_flags, Attributes attrs, Location loc)
40 : base (parent, constant_type, mod_flags, AllowedModifiers,
41 new MemberName (name, loc), attrs)
44 ModFlags |= Modifiers.STATIC;
47 protected override bool CheckBase ()
49 // Constant.Define can be called when the parent type hasn't yet been populated
50 // and it's base types need not have been populated. So, we defer this check
51 // to the second time Define () is called on this member.
52 if (Parent.PartialContainer.BaseCache == null)
54 return base.CheckBase ();
58 /// Defines the constant in the @parent
60 public override bool Define ()
62 // Because constant define can be called from other class
65 return FieldBuilder != null;
73 Type ttype = MemberType;
74 if (!IsConstantTypeValid (ttype)) {
75 Error_InvalidConstantType (ttype, Location);
80 ttype = TypeManager.GetElementType (ttype);
82 FieldAttributes field_attr = FieldAttributes.Static | Modifiers.FieldAttr (ModFlags);
83 // Decimals cannot be emitted into the constant blob. So, convert to 'readonly'.
84 if (ttype == TypeManager.decimal_type) {
85 field_attr |= FieldAttributes.InitOnly;
87 field_attr |= FieldAttributes.Literal;
90 FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType, field_attr);
91 TypeManager.RegisterConstant (FieldBuilder, this);
93 if (ttype == TypeManager.decimal_type)
94 Parent.PartialContainer.RegisterFieldForInitialization (this, new FieldInitializer (FieldBuilder, initializer));
99 public static bool IsConstantTypeValid (Type t)
101 if (TypeManager.IsBuiltinOrEnum (t))
104 if (t.IsPointer || t.IsValueType)
107 if (TypeManager.IsGenericParameter (t))
114 /// Emits the field value by evaluating the expression
116 public override void Emit ()
118 if (!ResolveValue ())
121 if (value.Type == TypeManager.decimal_type) {
122 Decimal d = ((DecimalConstant)value).Value;
123 int[] bits = Decimal.GetBits (d);
124 object[] args = new object[] { (byte)(bits [3] >> 16), (byte)(bits [3] >> 31), (uint)bits [2], (uint)bits [1], (uint)bits [0] };
125 CustomAttributeBuilder cab = new CustomAttributeBuilder (TypeManager.decimal_constant_attribute_ctor, args);
126 FieldBuilder.SetCustomAttribute (cab);
129 FieldBuilder.SetConstant (value.GetTypedValue ());
135 public static void Error_ExpressionMustBeConstant (Location loc, string e_name)
137 Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
140 public static void Error_CyclicDeclaration (MemberCore mc)
142 Report.Error (110, mc.Location, "The evaluation of the constant value for `{0}' involves a circular definition",
143 mc.GetSignatureForError ());
146 public static void Error_ConstantCanBeInitializedWithNullOnly (Location loc, string name)
148 Report.Error (134, loc, "`{0}': the constant of reference type other than string can only be initialized with null",
152 public static void Error_InvalidConstantType (Type t, Location loc)
154 Report.Error (283, loc, "The type `{0}' cannot be declared const", TypeManager.CSharpName (t));
157 #region IConstant Members
159 public bool ResolveValue ()
166 Error_CyclicDeclaration (this);
167 // Suppress cyclic errors
168 value = New.Constantify (MemberType);
173 // TODO: IResolveContext here
174 EmitContext ec = new EmitContext (this, Parent, Location, null, MemberType, ModFlags);
175 value = initializer.ResolveAsConstant (ec, this);
181 Constant c = value.ConvertImplicitly (MemberType);
183 if (!MemberType.IsValueType && MemberType != TypeManager.string_type && !value.IsDefaultValue)
184 Error_ConstantCanBeInitializedWithNullOnly (Location, GetSignatureForError ());
186 value.Error_ValueCannotBeConverted (null, Location, MemberType, false);
194 public Constant CreateConstantReference (Location loc)
199 return Constant.CreateConstant (value.Type, value.GetValue(), loc);
205 public class ExternalConstant : IConstant
210 public ExternalConstant (FieldInfo fi)
215 private ExternalConstant (FieldInfo fi, object value):
222 // Decimal constants cannot be encoded in the constant blob, and thus are marked
223 // as IsInitOnly ('readonly' in C# parlance). We get its value from the
224 // DecimalConstantAttribute metadata.
226 public static IConstant CreateDecimal (FieldInfo fi)
228 if (fi is FieldBuilder)
231 object[] attrs = fi.GetCustomAttributes (TypeManager.decimal_constant_attribute_type, false);
232 if (attrs.Length != 1)
235 IConstant ic = new ExternalConstant (fi,
236 ((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value);
241 #region IConstant Members
243 public void CheckObsoleteness (Location loc)
245 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (fi);
250 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (fi), loc);
253 public bool ResolveValue ()
258 value = fi.GetValue (fi);
262 public Constant CreateConstantReference (Location loc)
264 return Constant.CreateConstant (fi.FieldType, value, loc);