2 // const.cs: Constant declarations.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Copyright 2001-2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, 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 {
27 protected Constant value;
32 public const int AllowedModifiers =
39 public Const (DeclSpace parent, FullNamedExpression type, string name,
40 Expression expr, int mod_flags, Attributes attrs, Location loc)
41 : base (parent, type, mod_flags, AllowedModifiers,
42 new MemberName (name, loc), attrs)
45 ModFlags |= Modifiers.STATIC;
48 protected override bool CheckBase ()
50 // Constant.Define can be called when the parent type hasn't yet been populated
51 // and it's base types need not have been populated. So, we defer this check
52 // to the second time Define () is called on this member.
53 if (Parent.PartialContainer.BaseCache == null)
55 return base.CheckBase ();
59 /// Defines the constant in the @parent
61 public override bool Define ()
63 // Because constant define can be called from other class
66 return FieldBuilder != null;
74 Type ttype = MemberType;
75 if (!IsConstantTypeValid (ttype)) {
76 Error_InvalidConstantType (ttype, Location);
80 // If the constant is private then we don't need any field the
81 // value is already inlined and cannot be referenced
82 //if ((ModFlags & Modifiers.PRIVATE) != 0 && RootContext.Optimize)
86 ttype = TypeManager.GetElementType (ttype);
88 FieldAttributes field_attr = FieldAttributes.Static | Modifiers.FieldAttr (ModFlags);
89 // Decimals cannot be emitted into the constant blob. So, convert to 'readonly'.
90 if (ttype == TypeManager.decimal_type) {
91 field_attr |= FieldAttributes.InitOnly;
93 field_attr |= FieldAttributes.Literal;
96 FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType, field_attr);
97 TypeManager.RegisterConstant (FieldBuilder, this);
98 Parent.MemberCache.AddMember (FieldBuilder, this);
100 if (ttype == TypeManager.decimal_type)
101 Parent.PartialContainer.RegisterFieldForInitialization (this,
102 new FieldInitializer (FieldBuilder, initializer));
107 public static bool IsConstantTypeValid (Type t)
109 if (TypeManager.IsBuiltinOrEnum (t))
112 if (t.IsPointer || t.IsValueType)
115 if (TypeManager.IsGenericParameter (t))
122 /// Emits the field value by evaluating the expression
124 public override void Emit ()
126 if (!ResolveValue ())
129 if (FieldBuilder == null)
132 if (value.Type == TypeManager.decimal_type) {
133 EmitDecimalConstant ();
135 FieldBuilder.SetConstant (value.GetTypedValue ());
141 void EmitDecimalConstant ()
143 ConstructorInfo ctor = TypeManager.decimal_constant_attribute_ctor;
145 if (TypeManager.decimal_constant_attribute_type == null) {
146 TypeManager.decimal_constant_attribute_type = TypeManager.CoreLookupType (
147 "System.Runtime.CompilerServices", "DecimalConstantAttribute", Kind.Class, true);
149 if (TypeManager.decimal_constant_attribute_type == null)
153 ctor = TypeManager.GetPredefinedConstructor (TypeManager.decimal_constant_attribute_type, Location,
154 TypeManager.byte_type, TypeManager.byte_type,
155 TypeManager.uint32_type, TypeManager.uint32_type, TypeManager.uint32_type);
160 TypeManager.decimal_constant_attribute_ctor = ctor;
163 Decimal d = ((DecimalConstant) value).Value;
164 int [] bits = Decimal.GetBits (d);
165 object [] args = new object [] {
166 (byte) (bits [3] >> 16),
167 (byte) (bits [3] >> 31),
168 (uint) bits [2], (uint) bits [1], (uint) bits [0]
171 CustomAttributeBuilder cab = new CustomAttributeBuilder (ctor, args);
172 FieldBuilder.SetCustomAttribute (cab);
175 public static void Error_ExpressionMustBeConstant (Location loc, string e_name)
177 Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
180 public static void Error_CyclicDeclaration (MemberCore mc)
182 Report.Error (110, mc.Location, "The evaluation of the constant value for `{0}' involves a circular definition",
183 mc.GetSignatureForError ());
186 public static void Error_ConstantCanBeInitializedWithNullOnly (Location loc, string name)
188 Report.Error (134, loc, "`{0}': the constant of reference type other than string can only be initialized with null",
192 public static void Error_InvalidConstantType (Type t, Location loc)
194 Report.Error (283, loc, "The type `{0}' cannot be declared const", TypeManager.CSharpName (t));
197 #region IConstant Members
199 public bool ResolveValue ()
202 return value != null;
206 Error_CyclicDeclaration (this);
207 // Suppress cyclic errors
208 value = New.Constantify (MemberType);
214 // TODO: IResolveContext here
215 EmitContext ec = new EmitContext (
216 this, Parent, Location, null, MemberType, ModFlags);
217 ec.InEnumContext = this is EnumMember;
218 ec.IsAnonymousMethodAllowed = false;
219 value = DoResolveValue (ec);
222 return value != null;
225 protected virtual Constant DoResolveValue (EmitContext ec)
227 Constant value = initializer.ResolveAsConstant (ec, this);
231 Constant c = value.ConvertImplicitly (MemberType);
233 if (!MemberType.IsValueType && MemberType != TypeManager.string_type && !value.IsDefaultValue)
234 Error_ConstantCanBeInitializedWithNullOnly (Location, GetSignatureForError ());
236 value.Error_ValueCannotBeConverted (null, Location, MemberType, false);
242 public virtual Constant CreateConstantReference (Location loc)
247 return Constant.CreateConstant (value.Type, value.GetValue(), loc);
253 public class ExternalConstant : IConstant
258 public ExternalConstant (FieldInfo fi)
263 private ExternalConstant (FieldInfo fi, object value):
270 // Decimal constants cannot be encoded in the constant blob, and thus are marked
271 // as IsInitOnly ('readonly' in C# parlance). We get its value from the
272 // DecimalConstantAttribute metadata.
274 public static IConstant CreateDecimal (FieldInfo fi)
276 if (fi is FieldBuilder)
279 if (TypeManager.decimal_constant_attribute_type == null)
282 object[] attrs = fi.GetCustomAttributes (TypeManager.decimal_constant_attribute_type, false);
283 if (attrs.Length != 1)
286 IConstant ic = new ExternalConstant (fi,
287 ((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value);
292 #region IConstant Members
294 public void CheckObsoleteness (Location loc)
296 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (fi);
301 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (fi), loc);
304 public bool ResolveValue ()
309 value = fi.GetValue (fi);
313 public Constant CreateConstantReference (Location loc)
315 return Constant.CreateConstant (TypeManager.TypeToCoreType (fi.FieldType), value, loc);