cleol
[mcs.git] / mcs / const.cs
blobf25e56843da5450537ad30fd6f56b044ad265b0f
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 // Copyright 2001-2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
12 using System;
13 using System.Reflection;
14 using System.Reflection.Emit;
16 namespace Mono.CSharp {
18 public class Const : FieldBase
20 bool define_called;
22 public const Modifiers AllowedModifiers =
23 Modifiers.NEW |
24 Modifiers.PUBLIC |
25 Modifiers.PROTECTED |
26 Modifiers.INTERNAL |
27 Modifiers.PRIVATE;
29 public Const (DeclSpace parent, FullNamedExpression type, string name,
30 Expression expr, Modifiers mod_flags, Attributes attrs, Location loc)
31 : base (parent, type, mod_flags, AllowedModifiers,
32 new MemberName (name, loc), attrs)
34 if (expr != null)
35 initializer = new ConstInitializer (this, expr);
37 ModFlags |= Modifiers.STATIC;
40 protected override bool CheckBase ()
42 // Constant.Define can be called when the parent type hasn't yet been populated
43 // and it's base types need not have been populated. So, we defer this check
44 // to the second time Define () is called on this member.
45 if (Parent.PartialContainer.BaseCache == null)
46 return true;
47 return base.CheckBase ();
50 /// <summary>
51 /// Defines the constant in the @parent
52 /// </summary>
53 public override bool Define ()
55 // Because constant define can be called from other class
56 if (define_called) {
57 CheckBase ();
58 return FieldBuilder != null;
61 define_called = true;
63 if (!base.Define ())
64 return false;
66 Type ttype = MemberType;
67 if (!IsConstantTypeValid (ttype)) {
68 Error_InvalidConstantType (ttype, Location, Report);
71 FieldAttributes field_attr = FieldAttributes.Static | ModifiersExtensions.FieldAttr (ModFlags);
72 // Decimals cannot be emitted into the constant blob. So, convert to 'readonly'.
73 if (ttype == TypeManager.decimal_type) {
74 field_attr |= FieldAttributes.InitOnly;
75 } else {
76 field_attr |= FieldAttributes.Literal;
79 FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType, field_attr);
80 spec = new ConstSpec (this, FieldBuilder, ModFlags, initializer);
82 TypeManager.RegisterConstant (FieldBuilder, (ConstSpec) spec);
83 Parent.MemberCache.AddMember (FieldBuilder, spec);
85 if ((field_attr & FieldAttributes.InitOnly) != 0)
86 Parent.PartialContainer.RegisterFieldForInitialization (this,
87 new FieldInitializer (this, initializer, this));
89 return true;
92 public static bool IsConstantTypeValid (Type t)
94 if (TypeManager.IsBuiltinOrEnum (t))
95 return true;
97 if (TypeManager.IsGenericParameter (t) || t.IsPointer)
98 return false;
100 return TypeManager.IsReferenceType (t);
103 /// <summary>
104 /// Emits the field value by evaluating the expression
105 /// </summary>
106 public override void Emit ()
108 var value = initializer.Resolve (new ResolveContext (this)) as Constant;
109 if (value == null || FieldBuilder == null)
110 return;
112 if (value.Type == TypeManager.decimal_type) {
113 FieldBuilder.SetCustomAttribute (CreateDecimalConstantAttribute (value));
114 } else{
115 FieldBuilder.SetConstant (value.GetTypedValue ());
118 base.Emit ();
121 public static CustomAttributeBuilder CreateDecimalConstantAttribute (Constant c)
123 PredefinedAttribute pa = PredefinedAttributes.Get.DecimalConstant;
124 if (pa.Constructor == null &&
125 !pa.ResolveConstructor (c.Location, TypeManager.byte_type, TypeManager.byte_type,
126 TypeManager.uint32_type, TypeManager.uint32_type, TypeManager.uint32_type))
127 return null;
129 Decimal d = (Decimal) c.GetValue ();
130 int [] bits = Decimal.GetBits (d);
131 object [] args = new object [] {
132 (byte) (bits [3] >> 16),
133 (byte) (bits [3] >> 31),
134 (uint) bits [2], (uint) bits [1], (uint) bits [0]
137 return new CustomAttributeBuilder (pa.Constructor, args);
140 public static void Error_InvalidConstantType (Type t, Location loc, Report Report)
142 if (TypeManager.IsGenericParameter (t)) {
143 Report.Error (1959, loc,
144 "Type parameter `{0}' cannot be declared const", TypeManager.CSharpName (t));
145 } else {
146 Report.Error (283, loc,
147 "The type `{0}' cannot be declared const", TypeManager.CSharpName (t));
152 public class ConstSpec : FieldSpec
154 Expression value;
156 public ConstSpec (IMemberDefinition definition, FieldInfo fi, Modifiers mod, Expression value)
157 : base (definition, fi, mod)
159 this.value = value;
162 public Expression Value {
163 get {
164 return value;
166 set {
167 this.value = value;
172 class ConstInitializer : ShimExpression
174 bool in_transit;
175 protected readonly FieldBase field;
177 public ConstInitializer (FieldBase field, Expression value)
178 : base (value)
180 if (value != null)
181 this.loc = value.Location;
183 this.field = field;
186 protected override Expression DoResolve (ResolveContext unused)
188 if (type != null)
189 return expr;
191 var opt = ResolveContext.Options.ConstantScope;
192 if (field is EnumMember)
193 opt |= ResolveContext.Options.EnumScope;
196 // Use a context in which the constant was declared and
197 // not the one in which is referenced
199 var rc = new ResolveContext (field, opt);
200 expr = DoResolveInitializer (rc);
201 type = expr.Type;
203 return expr;
206 protected virtual Expression DoResolveInitializer (ResolveContext rc)
208 if (in_transit) {
209 field.Compiler.Report.Error (110, field.Location,
210 "The evaluation of the constant value for `{0}' involves a circular definition",
211 field.GetSignatureForError ());
213 expr = null;
214 } else {
215 in_transit = true;
216 expr = expr.Resolve (rc);
219 in_transit = false;
221 if (expr != null) {
222 Constant c = expr as Constant;
223 if (c != null)
224 c = field.ConvertInitializer (rc, c);
226 if (c == null) {
227 if (TypeManager.IsReferenceType (field.MemberType))
228 Error_ConstantCanBeInitializedWithNullOnly (rc, field.MemberType, loc, field.GetSignatureForError ());
229 else if (!(expr is Constant))
230 Error_ExpressionMustBeConstant (rc, field.Location, field.GetSignatureForError ());
231 else
232 expr.Error_ValueCannotBeConverted (rc, loc, field.MemberType, false);
235 expr = c;
238 if (expr == null) {
239 expr = New.Constantify (field.MemberType);
240 if (expr == null)
241 expr = Constant.CreateConstantFromValue (field.MemberType, null, Location);
242 expr = expr.Resolve (rc);
246 return expr;