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
20 public const Modifiers AllowedModifiers =
27 public Const (DeclSpace parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs)
28 : base (parent, type, mod_flags, AllowedModifiers, name, attrs)
30 ModFlags |= Modifiers.STATIC;
34 /// Defines the constant in the @parent
36 public override bool Define ()
41 if (!member_type.IsConstantCompatible) {
42 Error_InvalidConstantType (member_type, Location, Report);
45 FieldAttributes field_attr = FieldAttributes.Static | ModifiersExtensions.FieldAttr (ModFlags);
46 // Decimals cannot be emitted into the constant blob. So, convert to 'readonly'.
47 if (member_type == TypeManager.decimal_type) {
48 field_attr |= FieldAttributes.InitOnly;
50 field_attr |= FieldAttributes.Literal;
53 FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType.GetMetaInfo (), field_attr);
54 spec = new ConstSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags, initializer);
56 Parent.MemberCache.AddMember (spec);
58 if ((field_attr & FieldAttributes.InitOnly) != 0)
59 Parent.PartialContainer.RegisterFieldForInitialization (this,
60 new FieldInitializer (spec, initializer, this));
62 if (declarators != null) {
63 var t = new TypeExpression (MemberType, TypeExpression.Location);
64 int index = Parent.PartialContainer.Constants.IndexOf (this);
65 foreach (var d in declarators) {
66 var c = new Const (Parent, t, ModFlags & ~Modifiers.STATIC, new MemberName (d.Name.Value, d.Name.Location), OptAttributes);
67 c.initializer = d.Initializer;
68 ((ConstInitializer) c.initializer).Name = d.Name.Value;
69 Parent.PartialContainer.Constants.Insert (++index, c);
76 public void DefineValue ()
78 var rc = new ResolveContext (this);
79 ((ConstSpec) spec).GetConstant (rc);
83 /// Emits the field value by evaluating the expression
85 public override void Emit ()
87 var c = ((ConstSpec) spec).Value as Constant;
88 if (c.Type == TypeManager.decimal_type) {
89 FieldBuilder.SetCustomAttribute (CreateDecimalConstantAttribute (c, Compiler.PredefinedAttributes));
91 FieldBuilder.SetConstant (c.GetTypedValue ());
97 public static CustomAttributeBuilder CreateDecimalConstantAttribute (Constant c, PredefinedAttributes pa)
99 PredefinedAttribute attr = pa.DecimalConstant;
100 if (attr.Constructor == null &&
101 !attr.ResolveConstructor (c.Location, TypeManager.byte_type, TypeManager.byte_type,
102 TypeManager.uint32_type, TypeManager.uint32_type, TypeManager.uint32_type))
105 Decimal d = (Decimal) c.GetValue ();
106 int [] bits = Decimal.GetBits (d);
107 object [] args = new object [] {
108 (byte) (bits [3] >> 16),
109 (byte) (bits [3] >> 31),
110 (uint) bits [2], (uint) bits [1], (uint) bits [0]
113 return new CustomAttributeBuilder (attr.Constructor, args);
116 public static void Error_InvalidConstantType (TypeSpec t, Location loc, Report Report)
118 if (t.IsGenericParameter) {
119 Report.Error (1959, loc,
120 "Type parameter `{0}' cannot be declared const", TypeManager.CSharpName (t));
122 Report.Error (283, loc,
123 "The type `{0}' cannot be declared const", TypeManager.CSharpName (t));
128 public class ConstSpec : FieldSpec
132 public ConstSpec (TypeSpec declaringType, IMemberDefinition definition, TypeSpec memberType, FieldInfo fi, Modifiers mod, Expression value)
133 : base (declaringType, definition, memberType, fi, mod)
139 // This expresion is guarantee to be a constant at emit phase only
141 public Expression Value {
148 // For compiled constants we have to resolve the value as there could be constant dependecies. This
149 // is needed for imported constants too to get the right context type
151 public Constant GetConstant (ResolveContext rc)
153 if (value.eclass != ExprClass.Value)
154 value = value.Resolve (rc);
156 return (Constant) value;
160 public class ConstInitializer : ShimExpression
163 readonly FieldBase field;
165 public ConstInitializer (FieldBase field, Expression value, Location loc)
172 public string Name { get; set; }
174 protected override Expression DoResolve (ResolveContext unused)
179 var opt = ResolveContext.Options.ConstantScope;
180 if (field is EnumMember)
181 opt |= ResolveContext.Options.EnumScope;
184 // Use a context in which the constant was declared and
185 // not the one in which is referenced
187 var rc = new ResolveContext (field, opt);
188 expr = DoResolveInitializer (rc);
194 protected virtual Expression DoResolveInitializer (ResolveContext rc)
197 field.Compiler.Report.Error (110, expr.Location,
198 "The evaluation of the constant value for `{0}' involves a circular definition",
199 GetSignatureForError ());
204 expr = expr.Resolve (rc);
210 Constant c = expr as Constant;
212 c = field.ConvertInitializer (rc, c);
215 if (TypeManager.IsReferenceType (field.MemberType))
216 Error_ConstantCanBeInitializedWithNullOnly (rc, field.MemberType, expr.Location, GetSignatureForError ());
217 else if (!(expr is Constant))
218 Error_ExpressionMustBeConstant (rc, expr.Location, GetSignatureForError ());
220 expr.Error_ValueCannotBeConverted (rc, expr.Location, field.MemberType, false);
227 expr = New.Constantify (field.MemberType, Location);
229 expr = Constant.CreateConstantFromValue (field.MemberType, null, Location);
230 expr = expr.Resolve (rc);
236 public override string GetSignatureForError ()
239 return field.GetSignatureForError ();
241 return field.Parent.GetSignatureForError () + "." + Name;