2010-05-25 Jb Evain <jbevain@novell.com>
[mcs.git] / mcs / const.cs
blob6b502c04f2b2986eb189a973afd4b72362c157ae
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 Constant value;
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 /// <summary>
41 /// Defines the constant in the @parent
42 /// </summary>
43 public override bool Define ()
45 if (!base.Define ())
46 return false;
48 TypeSpec ttype = MemberType;
49 if (!ttype.IsConstantCompatible) {
50 Error_InvalidConstantType (ttype, Location, Report);
53 FieldAttributes field_attr = FieldAttributes.Static | ModifiersExtensions.FieldAttr (ModFlags);
54 // Decimals cannot be emitted into the constant blob. So, convert to 'readonly'.
55 if (ttype == TypeManager.decimal_type) {
56 field_attr |= FieldAttributes.InitOnly;
57 } else {
58 field_attr |= FieldAttributes.Literal;
61 FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType.GetMetaInfo (), field_attr);
62 spec = new ConstSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags, initializer);
64 Parent.MemberCache.AddMember (spec);
66 if ((field_attr & FieldAttributes.InitOnly) != 0)
67 Parent.PartialContainer.RegisterFieldForInitialization (this,
68 new FieldInitializer (this, initializer, this));
70 return true;
73 public Constant DefineValue ()
75 if (value == null)
76 value = initializer.Resolve (new ResolveContext (this)) as Constant;
78 return value;
81 /// <summary>
82 /// Emits the field value by evaluating the expression
83 /// </summary>
84 public override void Emit ()
86 if (value.Type == TypeManager.decimal_type) {
87 FieldBuilder.SetCustomAttribute (CreateDecimalConstantAttribute (value));
88 } else{
89 FieldBuilder.SetConstant (value.GetTypedValue ());
92 base.Emit ();
95 public static CustomAttributeBuilder CreateDecimalConstantAttribute (Constant c)
97 PredefinedAttribute pa = PredefinedAttributes.Get.DecimalConstant;
98 if (pa.Constructor == null &&
99 !pa.ResolveConstructor (c.Location, TypeManager.byte_type, TypeManager.byte_type,
100 TypeManager.uint32_type, TypeManager.uint32_type, TypeManager.uint32_type))
101 return null;
103 Decimal d = (Decimal) c.GetValue ();
104 int [] bits = Decimal.GetBits (d);
105 object [] args = new object [] {
106 (byte) (bits [3] >> 16),
107 (byte) (bits [3] >> 31),
108 (uint) bits [2], (uint) bits [1], (uint) bits [0]
111 return new CustomAttributeBuilder (pa.Constructor, args);
114 public static void Error_InvalidConstantType (TypeSpec t, Location loc, Report Report)
116 if (t.IsGenericParameter) {
117 Report.Error (1959, loc,
118 "Type parameter `{0}' cannot be declared const", TypeManager.CSharpName (t));
119 } else {
120 Report.Error (283, loc,
121 "The type `{0}' cannot be declared const", TypeManager.CSharpName (t));
126 public class ConstSpec : FieldSpec
128 Expression value;
130 public ConstSpec (TypeSpec declaringType, IMemberDefinition definition, TypeSpec memberType, FieldInfo fi, Modifiers mod, Expression value)
131 : base (declaringType, definition, memberType, fi, mod)
133 this.value = value;
136 public Expression Value {
137 get {
138 return value;
140 private set {
141 this.value = value;
146 class ConstInitializer : ShimExpression
148 bool in_transit;
149 protected readonly FieldBase field;
151 public ConstInitializer (FieldBase field, Expression value)
152 : base (value)
154 if (value != null)
155 this.loc = value.Location;
157 this.field = field;
160 protected override Expression DoResolve (ResolveContext unused)
162 if (type != null)
163 return expr;
165 var opt = ResolveContext.Options.ConstantScope;
166 if (field is EnumMember)
167 opt |= ResolveContext.Options.EnumScope;
170 // Use a context in which the constant was declared and
171 // not the one in which is referenced
173 var rc = new ResolveContext (field, opt);
174 expr = DoResolveInitializer (rc);
175 type = expr.Type;
177 return expr;
180 protected virtual Expression DoResolveInitializer (ResolveContext rc)
182 if (in_transit) {
183 field.Compiler.Report.Error (110, field.Location,
184 "The evaluation of the constant value for `{0}' involves a circular definition",
185 field.GetSignatureForError ());
187 expr = null;
188 } else {
189 in_transit = true;
190 expr = expr.Resolve (rc);
193 in_transit = false;
195 if (expr != null) {
196 Constant c = expr as Constant;
197 if (c != null)
198 c = field.ConvertInitializer (rc, c);
200 if (c == null) {
201 if (TypeManager.IsReferenceType (field.MemberType))
202 Error_ConstantCanBeInitializedWithNullOnly (rc, field.MemberType, loc, field.GetSignatureForError ());
203 else if (!(expr is Constant))
204 Error_ExpressionMustBeConstant (rc, field.Location, field.GetSignatureForError ());
205 else
206 expr.Error_ValueCannotBeConverted (rc, loc, field.MemberType, false);
209 expr = c;
212 if (expr == null) {
213 expr = New.Constantify (field.MemberType);
214 if (expr == null)
215 expr = Constant.CreateConstantFromValue (field.MemberType, null, Location);
216 expr = expr.Resolve (rc);
219 return expr;