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;
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)
47 return base.CheckBase ();
51 /// Defines the constant in the @parent
53 public override bool Define ()
55 // Because constant define can be called from other class
58 return FieldBuilder != null;
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;
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));
92 public static bool IsConstantTypeValid (Type t)
94 if (TypeManager.IsBuiltinOrEnum (t))
97 if (TypeManager.IsGenericParameter (t) || t.IsPointer)
100 return TypeManager.IsReferenceType (t);
104 /// Emits the field value by evaluating the expression
106 public override void Emit ()
108 var value = initializer.Resolve (new ResolveContext (this)) as Constant;
109 if (value == null || FieldBuilder == null)
112 if (value.Type == TypeManager.decimal_type) {
113 FieldBuilder.SetCustomAttribute (CreateDecimalConstantAttribute (value));
115 FieldBuilder.SetConstant (value.GetTypedValue ());
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))
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));
146 Report.Error (283, loc,
147 "The type `{0}' cannot be declared const", TypeManager.CSharpName (t));
152 public class ConstSpec : FieldSpec
156 public ConstSpec (IMemberDefinition definition, FieldInfo fi, Modifiers mod, Expression value)
157 : base (definition, fi, mod)
162 public Expression Value {
172 class ConstInitializer : ShimExpression
175 protected readonly FieldBase field;
177 public ConstInitializer (FieldBase field, Expression value)
181 this.loc = value.Location;
186 protected override Expression DoResolve (ResolveContext unused)
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);
206 protected virtual Expression DoResolveInitializer (ResolveContext rc)
209 field.Compiler.Report.Error (110, field.Location,
210 "The evaluation of the constant value for `{0}' involves a circular definition",
211 field.GetSignatureForError ());
216 expr = expr.Resolve (rc);
222 Constant c = expr as Constant;
224 c = field.ConvertInitializer (rc, c);
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 ());
232 expr.Error_ValueCannotBeConverted (rc, loc, field.MemberType, false);
239 expr = New.Constantify (field.MemberType);
241 expr = Constant.CreateConstantFromValue (field.MemberType, null, Location);
242 expr = expr.Resolve (rc);