This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[mono.git] / mcs / mcs / const.cs
1 //
2 // const.cs: Constant declarations.
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) 2001 Ximian, Inc.
8 //
9 //
10
11 //
12 // This is needed because the following situation arises:
13 //
14 //     The FieldBuilder is declared with the real type for an enumeration
15 //
16 //     When we attempt to set the value for the constant, the FieldBuilder.SetConstant
17 //     function aborts because it requires its argument to be of the same type
18 //
19
20 namespace Mono.CSharp {
21
22         using System;
23         using System.Reflection;
24         using System.Reflection.Emit;
25         using System.Collections;
26
27         public class Const : FieldBase {
28                 public Expression Expr;
29                 EmitContext const_ec;
30
31                 bool resolved = false;
32                 object ConstantValue = null;
33                 Type type;
34
35                 bool in_transit = false;
36
37                 public const int AllowedModifiers =
38                         Modifiers.NEW |
39                         Modifiers.PUBLIC |
40                         Modifiers.PROTECTED |
41                         Modifiers.INTERNAL |
42                         Modifiers.PRIVATE;
43
44                 public Const (Expression constant_type, string name, Expression expr, int mod_flags,
45                               Attributes attrs, Location loc)
46                         : base (constant_type, mod_flags, AllowedModifiers, name, null, attrs, loc)
47                 {
48                         Expr = expr;
49                 }
50
51                 public FieldAttributes FieldAttr {
52                         get {
53                                 return FieldAttributes.Literal | FieldAttributes.Static |
54                                         Modifiers.FieldAttr (ModFlags) ;
55                         }
56                 }
57
58 #if DEBUG
59                 void dump_tree (Type t)
60                 {
61                         Console.WriteLine ("Dumping hierarchy");
62                         while (t != null){
63                                 Console.WriteLine ("   " + t.FullName + " " +
64                                         (t.GetType ().IsEnum ? "yes" : "no"));
65                                 t = t.BaseType;
66                         }
67                 }
68 #endif
69
70                 /// <summary>
71                 ///   Defines the constant in the @parent
72                 /// </summary>
73                 public override bool Define (TypeContainer parent)
74                 {
75                         type = parent.ResolveType (Type, false, Location);
76
77                         if (type == null)
78                                 return false;
79
80                         const_ec = new EmitContext (parent, Location, null, type, ModFlags);
81
82                         Type ttype = type;
83                         while (ttype.IsArray)
84                             ttype = TypeManager.GetElementType (ttype);
85                         
86                         if (!TypeManager.IsBuiltinType (ttype) &&
87                             (!ttype.IsSubclassOf (TypeManager.enum_type))) {
88                                 Report.Error (
89                                         -3, Location,
90                                         "Constant type is not valid (only system types are allowed)");
91                                 return false;
92                         }
93
94                         Type ptype = parent.TypeBuilder.BaseType;
95
96                         if (ptype != null) {
97                                 MemberList list = TypeContainer.FindMembers (
98                                         ptype, MemberTypes.Field, BindingFlags.Public,
99                                         System.Type.FilterName, Name);
100                                 
101                                 if (list.Count == 0)
102                                         if ((ModFlags & Modifiers.NEW) != 0)
103                                                 WarningNotHiding (parent);
104
105                         } else if ((ModFlags & Modifiers.NEW) != 0)
106                                 WarningNotHiding (parent);
107
108                         FieldBuilder = parent.TypeBuilder.DefineField (Name, type, FieldAttr);
109
110                         TypeManager.RegisterConstant (FieldBuilder, this);
111
112                         return true;
113                 }
114
115                 //
116                 // Changes the type of the constant expression `expr' to the Type `type'
117                 // Returns null on failure.
118                 //
119                 public static Constant ChangeType (Location loc, Constant expr, Type type)
120                 {
121                         if (type == TypeManager.object_type)
122                                 return expr;
123
124                         bool fail;
125
126                         // from the null type to any reference-type.
127                         if (expr is NullLiteral && !type.IsValueType && !TypeManager.IsEnumType (type))
128                                 return NullLiteral.Null;
129
130                         if (!Convert.ImplicitStandardConversionExists (expr, type)){
131                                 Convert.Error_CannotImplicitConversion (loc, expr.Type, type);
132                                 return null;
133                         }
134                         
135                         object constant_value = TypeManager.ChangeType (expr.GetValue (), type, out fail);
136                         if (fail){
137                                 Convert.Error_CannotImplicitConversion (loc, expr.Type, type);
138                                 
139                                 //
140                                 // We should always catch the error before this is ever
141                                 // reached, by calling Convert.ImplicitStandardConversionExists
142                                 //
143                                 throw new Exception (
144                                                      String.Format ("LookupConstantValue: This should never be reached {0} {1}", expr.Type, type));
145                         }
146
147                         Constant retval;
148                         if (type == TypeManager.int32_type)
149                                 retval = new IntConstant ((int) constant_value);
150                         else if (type == TypeManager.uint32_type)
151                                 retval = new UIntConstant ((uint) constant_value);
152                         else if (type == TypeManager.int64_type)
153                                 retval = new LongConstant ((long) constant_value);
154                         else if (type == TypeManager.uint64_type)
155                                 retval = new ULongConstant ((ulong) constant_value);
156                         else if (type == TypeManager.float_type)
157                                 retval = new FloatConstant ((float) constant_value);
158                         else if (type == TypeManager.double_type)
159                                 retval = new DoubleConstant ((double) constant_value);
160                         else if (type == TypeManager.string_type)
161                                 retval = new StringConstant ((string) constant_value);
162                         else if (type == TypeManager.short_type)
163                                 retval = new ShortConstant ((short) constant_value);
164                         else if (type == TypeManager.ushort_type)
165                                 retval = new UShortConstant ((ushort) constant_value);
166                         else if (type == TypeManager.sbyte_type)
167                                 retval = new SByteConstant ((sbyte) constant_value);
168                         else if (type == TypeManager.byte_type)
169                                 retval = new ByteConstant ((byte) constant_value);
170                         else if (type == TypeManager.char_type)
171                                 retval = new CharConstant ((char) constant_value);
172                         else if (type == TypeManager.bool_type)
173                                 retval = new BoolConstant ((bool) constant_value);
174                         else
175                                 throw new Exception ("LookupConstantValue: Unhandled constant type: " + type);
176                         
177                         return retval;
178                 }
179                 
180                 /// <summary>
181                 ///  Looks up the value of a constant field. Defines it if it hasn't
182                 ///  already been. Similar to LookupEnumValue in spirit.
183                 /// </summary>
184                 public bool LookupConstantValue (out object value)
185                 {
186                         if (resolved) {
187                                 value = ConstantValue;
188                                 return true;
189                         }
190
191                         if (in_transit) {
192                                 Report.Error (110, Location,
193                                               "The evaluation of the constant value for `" +
194                                               Name + "' involves a circular definition.");
195                                 value = null;
196                                 return false;
197                         }
198
199                         in_transit = true;
200                         int errors = Report.Errors;
201
202                         //
203                         // We might have cleared Expr ourselves in a recursive definition
204                         //
205                         if (Expr == null){
206                                 value = null;
207                                 return false;
208                         }
209
210                         Expr = Expr.Resolve (const_ec);
211
212                         in_transit = false;
213
214                         if (Expr == null) {
215                                 if (errors == Report.Errors)
216                                         Report.Error (150, Location, "A constant value is expected");
217                                 value = null;
218                                 return false;
219                         }
220
221                         Expression real_expr = Expr;
222
223                         Constant ce = Expr as Constant;
224                         if (ce == null){
225                                 UnCheckedExpr un_expr = Expr as UnCheckedExpr;
226                                 CheckedExpr ch_expr = Expr as CheckedExpr;
227                                 EmptyCast ec_expr = Expr as EmptyCast;
228
229                                 if ((un_expr != null) && (un_expr.Expr is Constant))
230                                         Expr = un_expr.Expr;
231                                 else if ((ch_expr != null) && (ch_expr.Expr is Constant))
232                                         Expr = ch_expr.Expr;
233                                 else if ((ec_expr != null) && (ec_expr.Child is Constant))
234                                         Expr = ec_expr.Child;
235                                 else if (Expr is ArrayCreation) {
236                                         ArrayCreation ac = (ArrayCreation) Expr;
237
238                                         Expr = ac.TurnIntoConstant ();
239                                         if (Expr == null){
240                                                 Report.Error (150, Location, "A constant value is expected");
241                                                 value = null;
242                                                 return false;
243                                         }
244                                 } else {
245                                         if (errors == Report.Errors)
246                                                 Report.Error (150, Location, "A constant value is expected");
247                                         value = null;
248                                         return false;
249                                 }
250
251                                 ce = Expr as Constant;
252                         }
253
254                         if (type != real_expr.Type) {
255                                 ce = ChangeType (Location, ce, type);
256                                 if (ce == null){
257                                         value = null;
258                                         return false;
259                                 }
260                                 Expr = ce;
261                         }
262                         ConstantValue = ce.GetValue ();
263
264                         if (type.IsEnum){
265                                 //
266                                 // This sadly does not work for our user-defined enumerations types ;-(
267                                 //
268                                 try {
269                                         ConstantValue = System.Enum.ToObject (
270                                                 type, ConstantValue);
271                                 } catch (ArgumentException){
272                                         Report.Error (
273                                                 -16, Location,
274                                                 ".NET SDK 1.0 does not permit to create the constant "+
275                                                 " field from a user-defined enumeration");
276                                 }
277                         }
278
279                         FieldBuilder.SetConstant (ConstantValue);
280
281                         if (!TypeManager.RegisterFieldValue (FieldBuilder, ConstantValue))
282                                 throw new Exception ("Cannot register const value");
283
284                         value = ConstantValue;
285                         resolved = true;
286                         return true;
287                 }
288                 
289                 
290                 /// <summary>
291                 ///  Emits the field value by evaluating the expression
292                 /// </summary>
293                 public override void Emit (TypeContainer parent)
294                 {
295                         object value;
296                         LookupConstantValue (out value);
297
298                         if (OptAttributes != null) {
299                                 OptAttributes.Emit (const_ec, this);
300                         }
301
302                         base.Emit (parent);
303                 }
304         }
305 }
306
307