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.
15 using IKVM.Reflection;
17 using System.Reflection;
20 namespace Mono.CSharp {
22 public class Const : FieldBase
24 const Modifiers AllowedModifiers =
31 public Const (TypeDefinition parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs)
32 : base (parent, type, mod_flags, AllowedModifiers, name, attrs)
34 ModFlags |= Modifiers.STATIC;
38 /// Defines the constant in the @parent
40 public override bool Define ()
45 if (!member_type.IsConstantCompatible) {
46 Error_InvalidConstantType (member_type, Location, Report);
49 FieldAttributes field_attr = FieldAttributes.Static | ModifiersExtensions.FieldAttr (ModFlags);
50 // Decimals cannot be emitted into the constant blob. So, convert to 'readonly'.
51 if (member_type.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
52 field_attr |= FieldAttributes.InitOnly;
54 field_attr |= FieldAttributes.Literal;
57 FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType.GetMetaInfo (), field_attr);
58 spec = new ConstSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags, initializer);
60 Parent.MemberCache.AddMember (spec);
62 if ((field_attr & FieldAttributes.InitOnly) != 0)
63 Parent.PartialContainer.RegisterFieldForInitialization (this,
64 new FieldInitializer (this, initializer, Location));
66 if (declarators != null) {
67 var t = new TypeExpression (MemberType, TypeExpression.Location);
68 foreach (var d in declarators) {
69 var c = new Const (Parent, t, ModFlags & ~Modifiers.STATIC, new MemberName (d.Name.Value, d.Name.Location), OptAttributes);
70 c.initializer = d.Initializer;
71 ((ConstInitializer) c.initializer).Name = d.Name.Value;
73 Parent.PartialContainer.Members.Add (c);
80 public void DefineValue ()
82 var rc = new ResolveContext (this);
83 ((ConstSpec) spec).GetConstant (rc);
87 /// Emits the field value by evaluating the expression
89 public override void Emit ()
91 var c = ((ConstSpec) spec).Value as Constant;
92 if (c.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
93 Module.PredefinedAttributes.DecimalConstant.EmitAttribute (FieldBuilder, (decimal) c.GetValue (), c.Location);
95 FieldBuilder.SetConstant (c.GetValue ());
101 public static void Error_InvalidConstantType (TypeSpec t, Location loc, Report Report)
103 if (t.IsGenericParameter) {
104 Report.Error (1959, loc,
105 "Type parameter `{0}' cannot be declared const", t.GetSignatureForError ());
107 Report.Error (283, loc,
108 "The type `{0}' cannot be declared const", t.GetSignatureForError ());
112 public override void Accept (StructuralVisitor visitor)
114 visitor.Visit (this);
118 public class ConstSpec : FieldSpec
122 public ConstSpec (TypeSpec declaringType, IMemberDefinition definition, TypeSpec memberType, FieldInfo fi, Modifiers mod, Expression value)
123 : base (declaringType, definition, memberType, fi, mod)
126 throw new ArgumentNullException ("value");
132 // This expresion is guarantee to be a constant at emit phase only
134 public Expression Value {
141 // For compiled constants we have to resolve the value as there could be constant dependecies. This
142 // is needed for imported constants too to get the right context type
144 public Constant GetConstant (ResolveContext rc)
146 if (value.eclass != ExprClass.Value)
147 value = value.Resolve (rc);
149 return (Constant) value;
153 public class ConstInitializer : ShimExpression
156 readonly FieldBase field;
158 public ConstInitializer (FieldBase field, Expression value, Location loc)
165 public string Name { get; set; }
167 protected override Expression DoResolve (ResolveContext unused)
172 var opt = ResolveContext.Options.ConstantScope;
173 if (field is EnumMember)
174 opt |= ResolveContext.Options.EnumScope;
177 // Use a context in which the constant was declared and
178 // not the one in which is referenced
180 var rc = new ResolveContext (field, opt);
181 expr = DoResolveInitializer (rc);
187 protected virtual Expression DoResolveInitializer (ResolveContext rc)
190 field.Compiler.Report.Error (110, expr.Location,
191 "The evaluation of the constant value for `{0}' involves a circular definition",
192 GetSignatureForError ());
197 expr = expr.Resolve (rc);
203 Constant c = expr as Constant;
205 c = field.ConvertInitializer (rc, c);
208 if (TypeSpec.IsReferenceType (field.MemberType))
209 Error_ConstantCanBeInitializedWithNullOnly (rc, field.MemberType, expr.Location, GetSignatureForError ());
210 else if (!(expr is Constant))
211 Error_ExpressionMustBeConstant (rc, expr.Location, GetSignatureForError ());
213 expr.Error_ValueCannotBeConverted (rc, field.MemberType, false);
220 expr = New.Constantify (field.MemberType, Location);
222 expr = Constant.CreateConstantFromValue (field.MemberType, null, Location);
223 expr = expr.Resolve (rc);
229 public override string GetSignatureForError ()
232 return field.GetSignatureForError ();
234 return field.Parent.GetSignatureForError () + "." + Name;
237 public override object Accept (StructuralVisitor visitor)
239 return visitor.Visit (this);