In ilasm/tests:
[mcs.git] / mcs / const.cs
blob3282d6f24bf7ac4517b973687025af49294a0da7
1 //
2 // const.cs: Constant declarations.
3 //
4 // Author:
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
7 //
8 // (C) 2001 Ximian, Inc.
9 //
12 namespace Mono.CSharp {
14 using System;
15 using System.Reflection;
16 using System.Reflection.Emit;
17 using System.Collections;
19 public interface IConstant
21 void CheckObsoleteness (Location loc);
22 bool ResolveValue ();
23 Constant Value { get; }
26 public class Const : FieldMember, IConstant {
27 Constant value;
28 bool in_transit;
30 public const int AllowedModifiers =
31 Modifiers.NEW |
32 Modifiers.PUBLIC |
33 Modifiers.PROTECTED |
34 Modifiers.INTERNAL |
35 Modifiers.PRIVATE;
37 public Const (DeclSpace parent, Expression constant_type, string name,
38 Expression expr, int mod_flags, Attributes attrs, Location loc)
39 : base (parent, constant_type, mod_flags, AllowedModifiers,
40 new MemberName (name, loc), attrs)
42 initializer = expr;
43 ModFlags |= Modifiers.STATIC;
46 protected override bool CheckBase ()
48 // Constant.Define can be called when the parent type hasn't yet been populated
49 // and it's base types need not have been populated. So, we defer this check
50 // to the second time Define () is called on this member.
51 if (ParentContainer.BaseCache == null)
52 return true;
53 return base.CheckBase ();
56 /// <summary>
57 /// Defines the constant in the @parent
58 /// </summary>
59 public override bool Define ()
61 // Make Define () idempotent, but ensure that the error check happens.
62 if (FieldBuilder != null)
63 return base.CheckBase ();
65 if (!base.Define ())
66 return false;
68 Type ttype = MemberType;
69 while (ttype.IsArray)
70 ttype = TypeManager.GetElementType (ttype);
72 FieldAttributes field_attr = FieldAttributes.Static | Modifiers.FieldAttr (ModFlags);
73 // Decimals cannot be emitted into the constant blob. So, convert to 'readonly'.
74 if (ttype == TypeManager.decimal_type) {
75 field_attr |= FieldAttributes.InitOnly;
76 ParentContainer.RegisterFieldForInitialization (this);
78 else {
79 field_attr |= FieldAttributes.Literal;
82 FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType, field_attr);
84 TypeManager.RegisterConstant (FieldBuilder, this);
86 return true;
89 /// <summary>
90 /// Emits the field value by evaluating the expression
91 /// </summary>
92 public override void Emit ()
94 if (!ResolveValue ())
95 return;
97 if (value.Type == TypeManager.decimal_type) {
98 Decimal d = ((DecimalConstant)value).Value;
99 int[] bits = Decimal.GetBits (d);
100 object[] args = new object[] { (byte)(bits [3] >> 16), (byte)(bits [3] >> 31), (uint)bits [2], (uint)bits [1], (uint)bits [0] };
101 CustomAttributeBuilder cab = new CustomAttributeBuilder (TypeManager.decimal_constant_attribute_ctor, args);
102 FieldBuilder.SetCustomAttribute (cab);
104 else{
105 FieldBuilder.SetConstant (value.GetTypedValue ());
108 base.Emit ();
111 public static void Error_ExpressionMustBeConstant (Type constantType, Location loc, string e_name)
113 if (constantType != null && TypeManager.IsValueType (constantType) &&
114 !TypeManager.IsBuiltinOrEnum (constantType)) {
115 Report.Error (283, loc, "The type `{0}' cannot be declared const", TypeManager.CSharpName (constantType));
116 return;
118 Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
121 public static void Error_CyclicDeclaration (MemberCore mc)
123 Report.Error (110, mc.Location, "The evaluation of the constant value for `{0}' involves a circular definition",
124 mc.GetSignatureForError ());
127 public static void Error_ConstantCanBeInitializedWithNullOnly (Location loc, string name)
129 Report.Error (134, loc, "`{0}': the constant of reference type other than string can only be initialized with null",
130 name);
133 #region IConstant Members
135 public bool ResolveValue ()
137 if (value != null)
138 return true;
140 SetMemberIsUsed ();
141 if (in_transit) {
142 Error_CyclicDeclaration (this);
143 // Suppress cyclic errors
144 value = New.Constantify (MemberType);
145 return false;
148 in_transit = true;
149 // TODO: IResolveContext here
150 EmitContext ec = new EmitContext (this, Parent, Location, null, MemberType, ModFlags);
151 value = initializer.ResolveAsConstant (ec, this);
152 in_transit = false;
154 if (value == null)
155 return false;
157 value = value.ToType (MemberType, Location);
158 if (value == null)
159 return false;
161 if (!MemberType.IsValueType && MemberType != TypeManager.string_type && !value.IsDefaultValue) {
162 Error_ConstantCanBeInitializedWithNullOnly (Location, GetSignatureForError ());
163 return false;
166 return true;
169 public Constant Value {
170 get {
171 return value;
175 #endregion
178 public class ExternalConstant : IConstant
180 FieldInfo fi;
181 Constant value;
183 public ExternalConstant (FieldInfo fi)
185 this.fi = fi;
188 private ExternalConstant (FieldInfo fi, Constant value):
189 this (fi)
191 this.value = value;
195 // Decimal constants cannot be encoded in the constant blob, and thus are marked
196 // as IsInitOnly ('readonly' in C# parlance). We get its value from the
197 // DecimalConstantAttribute metadata.
199 public static IConstant CreateDecimal (FieldInfo fi)
201 if (fi is FieldBuilder)
202 return null;
204 object[] attrs = fi.GetCustomAttributes (TypeManager.decimal_constant_attribute_type, false);
205 if (attrs.Length != 1)
206 return null;
208 IConstant ic = new ExternalConstant (fi,
209 new DecimalConstant (((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value, Location.Null));
211 return ic;
214 #region IConstant Members
216 public void CheckObsoleteness (Location loc)
218 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (fi);
219 if (oa == null) {
220 return;
223 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (fi), loc);
226 public bool ResolveValue ()
228 if (value != null)
229 return true;
231 if (fi.DeclaringType.IsEnum) {
232 value = Expression.Constantify (fi.GetValue (fi), TypeManager.EnumToUnderlying (fi.FieldType));
233 value = new EnumConstant (value, fi.DeclaringType);
234 return true;
237 value = Expression.Constantify (fi.GetValue (fi), fi.FieldType);
238 return true;
241 public Constant Value {
242 get {
243 return value;
247 #endregion