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.
13 using System.Reflection;
14 using System.Reflection.Emit;
16 namespace Mono.CSharp {
18 public class Const : FieldBase
22 public const Modifiers AllowedModifiers =
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)
35 initializer = new ConstInitializer (this, expr);
37 ModFlags |= Modifiers.STATIC;
41 /// Defines the constant in the @parent
43 public override bool Define ()
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;
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));
73 public Constant DefineValue ()
76 value = initializer.Resolve (new ResolveContext (this)) as Constant;
82 /// Emits the field value by evaluating the expression
84 public override void Emit ()
86 if (value.Type == TypeManager.decimal_type) {
87 FieldBuilder.SetCustomAttribute (CreateDecimalConstantAttribute (value));
89 FieldBuilder.SetConstant (value.GetTypedValue ());
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))
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));
120 Report.Error (283, loc,
121 "The type `{0}' cannot be declared const", TypeManager.CSharpName (t));
126 public class ConstSpec : FieldSpec
130 public ConstSpec (TypeSpec declaringType, IMemberDefinition definition, TypeSpec memberType, FieldInfo fi, Modifiers mod, Expression value)
131 : base (declaringType, definition, memberType, fi, mod)
136 public Expression Value {
146 class ConstInitializer : ShimExpression
149 protected readonly FieldBase field;
151 public ConstInitializer (FieldBase field, Expression value)
155 this.loc = value.Location;
160 protected override Expression DoResolve (ResolveContext unused)
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);
180 protected virtual Expression DoResolveInitializer (ResolveContext rc)
183 field.Compiler.Report.Error (110, field.Location,
184 "The evaluation of the constant value for `{0}' involves a circular definition",
185 field.GetSignatureForError ());
190 expr = expr.Resolve (rc);
196 Constant c = expr as Constant;
198 c = field.ConvertInitializer (rc, c);
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 ());
206 expr.Error_ValueCannotBeConverted (rc, loc, field.MemberType, false);
213 expr = New.Constantify (field.MemberType);
215 expr = Constant.CreateConstantFromValue (field.MemberType, null, Location);
216 expr = expr.Resolve (rc);