[eglib] Prefer <langinfo.h> to <localcharset.h>
[mono.git] / mcs / mcs / const.cs
1 //
2 // const.cs: Constant declarations.
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Marek Safar (marek.safar@seznam.cz)
7 //
8 // Copyright 2001-2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 //
11
12 #if STATIC
13 using IKVM.Reflection;
14 #else
15 using System.Reflection;
16 #endif
17
18 namespace Mono.CSharp {
19
20         public class Const : FieldBase
21         {
22                 const Modifiers AllowedModifiers =
23                         Modifiers.NEW |
24                         Modifiers.PUBLIC |
25                         Modifiers.PROTECTED |
26                         Modifiers.INTERNAL |
27                         Modifiers.PRIVATE;
28
29                 public Const (TypeDefinition parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs)
30                         : base (parent, type, mod_flags, AllowedModifiers, name, attrs)
31                 {
32                         ModFlags |= Modifiers.STATIC;
33                 }
34
35                 /// <summary>
36                 ///   Defines the constant in the @parent
37                 /// </summary>
38                 public override bool Define ()
39                 {
40                         if (!base.Define ())
41                                 return false;
42
43                         if (!member_type.IsConstantCompatible) {
44                                 Error_InvalidConstantType (member_type, Location, Report);
45                         }
46
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;
51                         } else {
52                                 field_attr |= FieldAttributes.Literal;
53                         }
54
55                         FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType.GetMetaInfo (), field_attr);
56                         spec = new ConstSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags, initializer);
57
58                         Parent.MemberCache.AddMember (spec);
59
60                         if ((field_attr & FieldAttributes.InitOnly) != 0)
61                                 Parent.PartialContainer.RegisterFieldForInitialization (this,
62                                         new FieldInitializer (this, initializer, Location));
63
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;
70                                         c.Define ();
71                                         Parent.PartialContainer.Members.Add (c);
72                                 }
73                         }
74
75                         return true;
76                 }
77
78                 public void DefineValue ()
79                 {
80                         var rc = new ResolveContext (this);
81                         ((ConstSpec) spec).GetConstant (rc);
82                 }
83
84                 /// <summary>
85                 ///  Emits the field value by evaluating the expression
86                 /// </summary>
87                 public override void Emit ()
88                 {
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);
92                         } else {
93                                 FieldBuilder.SetConstant (c.GetValue ());
94                         }
95
96                         base.Emit ();
97                 }
98
99                 public static void Error_InvalidConstantType (TypeSpec t, Location loc, Report Report)
100                 {
101                         if (t.IsGenericParameter) {
102                                 Report.Error (1959, loc,
103                                         "Type parameter `{0}' cannot be declared const", t.GetSignatureForError ());
104                         } else {
105                                 Report.Error (283, loc,
106                                         "The type `{0}' cannot be declared const", t.GetSignatureForError ());
107                         }
108                 }
109
110                 public override void Accept (StructuralVisitor visitor)
111                 {
112                         visitor.Visit (this);
113                 }
114         }
115
116         public class ConstSpec : FieldSpec
117         {
118                 Expression value;
119
120                 public ConstSpec (TypeSpec declaringType, IMemberDefinition definition, TypeSpec memberType, FieldInfo fi, Modifiers mod, Expression value)
121                         : base (declaringType, definition, memberType, fi, mod)
122                 {
123                         this.value = value;
124                 }
125
126                 //
127                 // This expresion is guarantee to be a constant at emit phase only
128                 //
129                 public Expression Value {
130                         get {
131                                 return value;
132                         }
133                 }
134
135                 //
136                 // For compiled constants we have to resolve the value as there could be constant dependecies. This
137                 // is needed for imported constants too to get the right context type
138                 //
139                 public Constant GetConstant (ResolveContext rc)
140                 {
141                         if (value.eclass != ExprClass.Value)
142                                 value = value.Resolve (rc);
143
144                         return (Constant) value;
145                 }
146         }
147
148         public class ConstInitializer : ShimExpression
149         {
150                 bool in_transit;
151                 readonly FieldBase field;
152
153                 public ConstInitializer (FieldBase field, Expression value, Location loc)
154                         : base (value)
155                 {
156                         this.loc = loc;
157                         this.field = field;
158                 }
159
160                 public string Name { get; set; }
161
162                 protected override Expression DoResolve (ResolveContext unused)
163                 {
164                         if (type != null)
165                                 return expr;
166
167                         var opt = ResolveContext.Options.ConstantScope;
168                         if (field is EnumMember)
169                                 opt |= ResolveContext.Options.EnumScope;
170
171                         //
172                         // Use a context in which the constant was declared and
173                         // not the one in which is referenced
174                         //
175                         var rc = new ResolveContext (field, opt);
176                         expr = DoResolveInitializer (rc);
177                         type = expr.Type;
178
179                         return expr;
180                 }
181
182                 protected virtual Expression DoResolveInitializer (ResolveContext rc)
183                 {
184                         if (in_transit) {
185                                 field.Compiler.Report.Error (110, expr.Location,
186                                         "The evaluation of the constant value for `{0}' involves a circular definition",
187                                         GetSignatureForError ());
188
189                                 expr = null;
190                         } else {
191                                 in_transit = true;
192                                 expr = expr.Resolve (rc);
193                         }
194
195                         in_transit = false;
196
197                         if (expr != null) {
198                                 Constant c = expr as Constant;
199                                 if (c != null)
200                                         c = field.ConvertInitializer (rc, c);
201
202                                 if (c == null) {
203                                         if (TypeSpec.IsReferenceType (field.MemberType))
204                                                 Error_ConstantCanBeInitializedWithNullOnly (rc, field.MemberType, expr.Location, GetSignatureForError ());
205                                         else if (!(expr is Constant))
206                                                 Error_ExpressionMustBeConstant (rc, expr.Location, GetSignatureForError ());
207                                         else
208                                                 expr.Error_ValueCannotBeConverted (rc, field.MemberType, false);
209                                 }
210
211                                 expr = c;
212                         }
213
214                         if (expr == null) {
215                                 expr = New.Constantify (field.MemberType, Location);
216                                 if (expr == null)
217                                         expr = Constant.CreateConstantFromValue (field.MemberType, null, Location);
218                                 expr = expr.Resolve (rc);
219                         }
220
221                         return expr;
222                 }
223
224                 public override string GetSignatureForError ()
225                 {
226                         if (Name == null)
227                                 return field.GetSignatureForError ();
228
229                         return field.Parent.GetSignatureForError () + "." + Name;
230                 }
231
232                 public override object Accept (StructuralVisitor visitor)
233                 {
234                         return visitor.Visit (this);
235                 }
236         }
237 }