CS1526 error recovery
[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 namespace Mono.CSharp {
13
14         using System;
15         using System.Reflection;
16         using System.Reflection.Emit;
17         using System.Collections;
18
19         public interface IConstant
20         {
21                 void CheckObsoleteness (Location loc);
22                 bool ResolveValue ();
23                 Constant CreateConstantReference (Location loc);
24         }
25
26         public class Const : FieldBase, IConstant {
27                 protected Constant value;
28                 bool in_transit;
29                 bool resolved;
30                 bool define_called;
31
32                 public const int AllowedModifiers =
33                         Modifiers.NEW |
34                         Modifiers.PUBLIC |
35                         Modifiers.PROTECTED |
36                         Modifiers.INTERNAL |
37                         Modifiers.PRIVATE;
38
39                 public Const (DeclSpace parent, FullNamedExpression type, string name,
40                               Expression expr, int mod_flags, Attributes attrs, Location loc)
41                         : base (parent, type, mod_flags, AllowedModifiers,
42                                 new MemberName (name, loc), attrs)
43                 {
44                         initializer = expr;
45                         ModFlags |= Modifiers.STATIC;
46                 }
47
48                 protected override bool CheckBase ()
49                 {
50                         // Constant.Define can be called when the parent type hasn't yet been populated
51                         // and it's base types need not have been populated.  So, we defer this check
52                         // to the second time Define () is called on this member.
53                         if (Parent.PartialContainer.BaseCache == null)
54                                 return true;
55                         return base.CheckBase ();
56                 }
57
58                 /// <summary>
59                 ///   Defines the constant in the @parent
60                 /// </summary>
61                 public override bool Define ()
62                 {
63                         // Because constant define can be called from other class
64                         if (define_called) {
65                                 CheckBase ();
66                                 return FieldBuilder != null;
67                         }
68
69                         define_called = true;
70
71                         if (!base.Define ())
72                                 return false;
73
74                         Type ttype = MemberType;
75                         if (!IsConstantTypeValid (ttype)) {
76                                 Error_InvalidConstantType (ttype, Location, Report);
77                         }
78
79                         // If the constant is private then we don't need any field the
80                         // value is already inlined and cannot be referenced
81                         //if ((ModFlags & Modifiers.PRIVATE) != 0 && RootContext.Optimize)
82                         //      return true;
83
84                         FieldAttributes field_attr = FieldAttributes.Static | Modifiers.FieldAttr (ModFlags);
85                         // Decimals cannot be emitted into the constant blob.  So, convert to 'readonly'.
86                         if (ttype == TypeManager.decimal_type) {
87                                 field_attr |= FieldAttributes.InitOnly;
88                         } else {
89                                 field_attr |= FieldAttributes.Literal;
90                         }
91
92                         FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType, field_attr);
93                         TypeManager.RegisterConstant (FieldBuilder, this);
94                         Parent.MemberCache.AddMember (FieldBuilder, this);
95
96                         if ((field_attr & FieldAttributes.InitOnly) != 0)
97                                 Parent.PartialContainer.RegisterFieldForInitialization (this,
98                                         new FieldInitializer (FieldBuilder, initializer, this));
99
100                         return true;
101                 }
102
103                 public static bool IsConstantTypeValid (Type t)
104                 {
105                         if (TypeManager.IsBuiltinOrEnum (t))
106                                 return true;
107
108                         if (TypeManager.IsGenericParameter (t) || t.IsPointer)
109                                 return false;
110
111                         return TypeManager.IsReferenceType (t);
112                 }
113
114                 /// <summary>
115                 ///  Emits the field value by evaluating the expression
116                 /// </summary>
117                 public override void Emit ()
118                 {
119                         if (!ResolveValue ())
120                                 return;
121
122                         if (FieldBuilder == null)
123                                 return;
124
125                         if (value.Type == TypeManager.decimal_type) {
126                                 FieldBuilder.SetCustomAttribute (CreateDecimalConstantAttribute (value));
127                         } else{
128                                 FieldBuilder.SetConstant (value.GetTypedValue ());
129                         }
130
131                         base.Emit ();
132                 }
133
134                 public static CustomAttributeBuilder CreateDecimalConstantAttribute (Constant c)
135                 {
136                         PredefinedAttribute pa = PredefinedAttributes.Get.DecimalConstant;
137                         if (pa.Constructor == null &&
138                                 !pa.ResolveConstructor (c.Location, TypeManager.byte_type, TypeManager.byte_type,
139                                         TypeManager.uint32_type, TypeManager.uint32_type, TypeManager.uint32_type))
140                                 return null;
141
142                         Decimal d = (Decimal) c.GetValue ();
143                         int [] bits = Decimal.GetBits (d);
144                         object [] args = new object [] { 
145                                 (byte) (bits [3] >> 16),
146                                 (byte) (bits [3] >> 31),
147                                 (uint) bits [2], (uint) bits [1], (uint) bits [0]
148                         };
149
150                         return new CustomAttributeBuilder (pa.Constructor, args);
151                 }
152
153                 public static void Error_ExpressionMustBeConstant (Location loc, string e_name, Report Report)
154                 {
155                         Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
156                 }
157
158                 public static void Error_CyclicDeclaration (MemberCore mc, Report Report)
159                 {
160                         Report.Error (110, mc.Location, "The evaluation of the constant value for `{0}' involves a circular definition",
161                                 mc.GetSignatureForError ());
162                 }
163
164                 public static void Error_ConstantCanBeInitializedWithNullOnly (Type type, Location loc, string name, Report Report)
165                 {
166                         Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
167                                 name, TypeManager.CSharpName (type));
168                 }
169
170                 public static void Error_InvalidConstantType (Type t, Location loc, Report Report)
171                 {
172                         if (TypeManager.IsGenericParameter (t)) {
173                                 Report.Error (1959, loc,
174                                         "Type parameter `{0}' cannot be declared const", TypeManager.CSharpName (t));
175                         } else {
176                                 Report.Error (283, loc,
177                                         "The type `{0}' cannot be declared const", TypeManager.CSharpName (t));
178                         }
179                 }
180
181                 #region IConstant Members
182
183                 public bool ResolveValue ()
184                 {
185                         if (resolved)
186                                 return value != null;
187
188                         SetMemberIsUsed ();
189                         if (in_transit) {
190                                 Error_CyclicDeclaration (this, Report);
191                                 // Suppress cyclic errors
192                                 value = New.Constantify (MemberType);
193                                 resolved = true;
194                                 return false;
195                         }
196
197                         in_transit = true;
198
199                         ResolveContext.Options opt = ResolveContext.Options.ConstantScope;
200                         if (this is EnumMember)
201                                 opt |= ResolveContext.Options.EnumScope;
202
203                         ResolveContext rc = new ResolveContext (this, opt);
204                         value = DoResolveValue (rc);
205
206                         in_transit = false;
207                         resolved = true;
208                         return value != null;
209                 }
210
211                 protected virtual Constant DoResolveValue (ResolveContext ec)
212                 {
213                         Constant value = initializer.ResolveAsConstant (ec, this);
214                         if (value == null)
215                                 return null;
216
217                         Constant c = value.ConvertImplicitly (MemberType);
218                         if (c == null) {
219                                 if (TypeManager.IsReferenceType (MemberType))
220                                         Error_ConstantCanBeInitializedWithNullOnly (MemberType, Location, GetSignatureForError (), Report);
221                                 else
222                                         value.Error_ValueCannotBeConverted (ec, Location, MemberType, false);
223                         }
224
225                         return c;
226                 }
227
228                 public virtual Constant CreateConstantReference (Location loc)
229                 {
230                         if (value == null)
231                                 return null;
232
233                         return Constant.CreateConstant (value.Type, value.GetValue(), loc);
234                 }
235
236                 #endregion
237         }
238
239         public class ExternalConstant : IConstant
240         {
241                 FieldInfo fi;
242                 object value;
243
244                 public ExternalConstant (FieldInfo fi)
245                 {
246                         this.fi = fi;
247                 }
248
249                 private ExternalConstant (FieldInfo fi, object value):
250                         this (fi)
251                 {
252                         this.value = value;
253                 }
254
255                 //
256                 // Decimal constants cannot be encoded in the constant blob, and thus are marked
257                 // as IsInitOnly ('readonly' in C# parlance).  We get its value from the 
258                 // DecimalConstantAttribute metadata.
259                 //
260                 public static IConstant CreateDecimal (FieldInfo fi)
261                 {
262                         if (fi is FieldBuilder)
263                                 return null;
264
265                         PredefinedAttribute pa = PredefinedAttributes.Get.DecimalConstant;
266                         if (!pa.IsDefined)
267                                 return null;
268
269                         object[] attrs = fi.GetCustomAttributes (pa.Type, false);
270                         if (attrs.Length != 1)
271                                 return null;
272
273                         IConstant ic = new ExternalConstant (fi,
274                                 ((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value);
275
276                         return ic;
277                 }
278
279                 #region IConstant Members
280
281                 public void CheckObsoleteness (Location loc)
282                 {
283                         ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (fi);
284                         if (oa == null) {
285                                 return;
286                         }
287
288                         AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (fi), loc, RootContext.ToplevelTypes.Compiler.Report);
289                 }
290
291                 public bool ResolveValue ()
292                 {
293                         if (value != null)
294                                 return true;
295
296                         value = fi.GetValue (fi);
297                         return true;
298                 }
299
300                 public Constant CreateConstantReference (Location loc)
301                 {
302                         return Constant.CreateConstant (TypeManager.TypeToCoreType (fi.FieldType), value, loc);
303                 }
304
305                 #endregion
306         }
307
308 }