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.
12 using System.Reflection;
14 namespace Mono.CSharp {
16 public class Const : FieldBase
18 public const Modifiers AllowedModifiers =
25 public Const (DeclSpace parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs)
26 : base (parent, type, mod_flags, AllowedModifiers, name, attrs)
28 ModFlags |= Modifiers.STATIC;
32 /// Defines the constant in the @parent
34 public override bool Define ()
39 if (!member_type.IsConstantCompatible) {
40 Error_InvalidConstantType (member_type, Location, Report);
43 FieldAttributes field_attr = FieldAttributes.Static | ModifiersExtensions.FieldAttr (ModFlags);
44 // Decimals cannot be emitted into the constant blob. So, convert to 'readonly'.
45 if (member_type == TypeManager.decimal_type) {
46 field_attr |= FieldAttributes.InitOnly;
48 field_attr |= FieldAttributes.Literal;
51 FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType.GetMetaInfo (), field_attr);
52 spec = new ConstSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags, initializer);
54 Parent.MemberCache.AddMember (spec);
56 if ((field_attr & FieldAttributes.InitOnly) != 0)
57 Parent.PartialContainer.RegisterFieldForInitialization (this,
58 new FieldInitializer (spec, initializer, this));
60 if (declarators != null) {
61 var t = new TypeExpression (MemberType, TypeExpression.Location);
62 int index = Parent.PartialContainer.Constants.IndexOf (this);
63 foreach (var d in declarators) {
64 var c = new Const (Parent, t, ModFlags & ~Modifiers.STATIC, new MemberName (d.Name.Value, d.Name.Location), OptAttributes);
65 c.initializer = d.Initializer;
66 ((ConstInitializer) c.initializer).Name = d.Name.Value;
67 Parent.PartialContainer.Constants.Insert (++index, c);
74 public void DefineValue ()
76 var rc = new ResolveContext (this);
77 ((ConstSpec) spec).GetConstant (rc);
81 /// Emits the field value by evaluating the expression
83 public override void Emit ()
85 var c = ((ConstSpec) spec).Value as Constant;
86 if (c.Type == TypeManager.decimal_type) {
87 Module.PredefinedAttributes.DecimalConstant.EmitAttribute (FieldBuilder, (decimal) c.GetValue (), c.Location);
89 FieldBuilder.SetConstant (c.GetValue ());
95 public static void Error_InvalidConstantType (TypeSpec t, Location loc, Report Report)
97 if (t.IsGenericParameter) {
98 Report.Error (1959, loc,
99 "Type parameter `{0}' cannot be declared const", TypeManager.CSharpName (t));
101 Report.Error (283, loc,
102 "The type `{0}' cannot be declared const", TypeManager.CSharpName (t));
107 public class ConstSpec : FieldSpec
111 public ConstSpec (TypeSpec declaringType, IMemberDefinition definition, TypeSpec memberType, FieldInfo fi, Modifiers mod, Expression value)
112 : base (declaringType, definition, memberType, fi, mod)
118 // This expresion is guarantee to be a constant at emit phase only
120 public Expression Value {
127 // For compiled constants we have to resolve the value as there could be constant dependecies. This
128 // is needed for imported constants too to get the right context type
130 public Constant GetConstant (ResolveContext rc)
132 if (value.eclass != ExprClass.Value)
133 value = value.Resolve (rc);
135 return (Constant) value;
139 public class ConstInitializer : ShimExpression
142 readonly FieldBase field;
144 public ConstInitializer (FieldBase field, Expression value, Location loc)
151 public string Name { get; set; }
153 protected override Expression DoResolve (ResolveContext unused)
158 var opt = ResolveContext.Options.ConstantScope;
159 if (field is EnumMember)
160 opt |= ResolveContext.Options.EnumScope;
163 // Use a context in which the constant was declared and
164 // not the one in which is referenced
166 var rc = new ResolveContext (field, opt);
167 expr = DoResolveInitializer (rc);
173 protected virtual Expression DoResolveInitializer (ResolveContext rc)
176 field.Compiler.Report.Error (110, expr.Location,
177 "The evaluation of the constant value for `{0}' involves a circular definition",
178 GetSignatureForError ());
183 expr = expr.Resolve (rc);
189 Constant c = expr as Constant;
191 c = field.ConvertInitializer (rc, c);
194 if (TypeManager.IsReferenceType (field.MemberType))
195 Error_ConstantCanBeInitializedWithNullOnly (rc, field.MemberType, expr.Location, GetSignatureForError ());
196 else if (!(expr is Constant))
197 Error_ExpressionMustBeConstant (rc, expr.Location, GetSignatureForError ());
199 expr.Error_ValueCannotBeConverted (rc, expr.Location, field.MemberType, false);
206 expr = New.Constantify (field.MemberType, Location);
208 expr = Constant.CreateConstantFromValue (field.MemberType, null, Location);
209 expr = expr.Resolve (rc);
215 public override string GetSignatureForError ()
218 return field.GetSignatureForError ();
220 return field.Parent.GetSignatureForError () + "." + Name;