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 IKVM.Reflection;
15 using System.Reflection;
18 namespace Mono.CSharp {
20 public class Const : FieldBase
22 const Modifiers AllowedModifiers =
29 public Const (TypeDefinition parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs)
30 : base (parent, type, mod_flags, AllowedModifiers, name, attrs)
32 ModFlags |= Modifiers.STATIC;
36 /// Defines the constant in the @parent
38 public override bool Define ()
43 if (!member_type.IsConstantCompatible) {
44 Error_InvalidConstantType (member_type, Location, Report);
47 FieldAttributes field_attr = FieldAttributes.Static | ModifiersExtensions.FieldAttr (ModFlags);
48 // Decimals cannot be emitted into the constant blob. So, convert to 'readonly'.
49 if (member_type.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
50 field_attr |= FieldAttributes.InitOnly;
52 field_attr |= FieldAttributes.Literal;
55 FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType.GetMetaInfo (), field_attr);
56 spec = new ConstSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags, initializer);
58 Parent.MemberCache.AddMember (spec);
60 if ((field_attr & FieldAttributes.InitOnly) != 0)
61 Parent.PartialContainer.RegisterFieldForInitialization (this,
62 new FieldInitializer (this, initializer, Location));
64 if (declarators != null) {
65 var t = new TypeExpression (MemberType, TypeExpression.Location);
66 foreach (var d in declarators) {
67 var c = new Const (Parent, t, ModFlags & ~Modifiers.STATIC, new MemberName (d.Name.Value, d.Name.Location), OptAttributes);
68 c.initializer = d.Initializer;
69 ((ConstInitializer) c.initializer).Name = d.Name.Value;
71 Parent.PartialContainer.Members.Add (c);
78 public void DefineValue ()
80 var rc = new ResolveContext (this);
81 ((ConstSpec) spec).GetConstant (rc);
85 /// Emits the field value by evaluating the expression
87 public override void Emit ()
89 var c = ((ConstSpec) spec).Value as Constant;
90 if (c.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
91 Module.PredefinedAttributes.DecimalConstant.EmitAttribute (FieldBuilder, (decimal) c.GetValue (), c.Location);
93 FieldBuilder.SetConstant (c.GetValue ());
99 public static void Error_InvalidConstantType (TypeSpec t, Location loc, Report Report)
101 if (t.IsGenericParameter) {
102 Report.Error (1959, loc,
103 "Type parameter `{0}' cannot be declared const", t.GetSignatureForError ());
105 Report.Error (283, loc,
106 "The type `{0}' cannot be declared const", t.GetSignatureForError ());
110 public override void Accept (StructuralVisitor visitor)
112 visitor.Visit (this);
115 public override void PrepareEmit ()
122 public class ConstSpec : FieldSpec
126 public ConstSpec (TypeSpec declaringType, IMemberDefinition definition, TypeSpec memberType, FieldInfo fi, Modifiers mod, Expression value)
127 : base (declaringType, definition, memberType, fi, mod)
133 // This expresion is guarantee to be a constant at emit phase only
135 public Expression Value {
142 // For compiled constants we have to resolve the value as there could be constant dependecies. This
143 // is needed for imported constants too to get the right context type
145 public Constant GetConstant (ResolveContext rc)
147 if (value.eclass != ExprClass.Value)
148 value = value.Resolve (rc);
150 return (Constant) value;
154 public class ConstInitializer : ShimExpression
157 readonly FieldBase field;
159 public ConstInitializer (FieldBase field, Expression value, Location loc)
166 public string Name { get; set; }
168 protected override Expression DoResolve (ResolveContext unused)
173 var opt = ResolveContext.Options.ConstantScope;
174 if (field is EnumMember)
175 opt |= ResolveContext.Options.EnumScope;
178 // Use a context in which the constant was declared and
179 // not the one in which is referenced
181 var rc = new ResolveContext (field, opt);
182 expr = DoResolveInitializer (rc);
188 protected virtual Expression DoResolveInitializer (ResolveContext rc)
191 field.Compiler.Report.Error (110, expr.Location,
192 "The evaluation of the constant value for `{0}' involves a circular definition",
193 GetSignatureForError ());
198 expr = expr.Resolve (rc);
204 Constant c = expr as Constant;
206 c = field.ConvertInitializer (rc, c);
209 if (TypeSpec.IsReferenceType (field.MemberType))
210 Error_ConstantCanBeInitializedWithNullOnly (rc, field.MemberType, expr.Location, GetSignatureForError ());
211 else if (!(expr is Constant))
212 Error_ExpressionMustBeConstant (rc, expr.Location, GetSignatureForError ());
214 expr.Error_ValueCannotBeConverted (rc, field.MemberType, false);
221 expr = New.Constantify (field.MemberType, Location);
223 expr = Constant.CreateConstantFromValue (field.MemberType, null, Location);
224 expr = expr.Resolve (rc);
230 public override string GetSignatureForError ()
233 return field.GetSignatureForError ();
235 return field.Parent.GetSignatureForError () + "." + Name;
238 public override object Accept (StructuralVisitor visitor)
240 return visitor.Visit (this);