2003-05-27 Miguel de Icaza <miguel@ximian.com>
[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 : MemberCore {
28                 public Expression ConstantType;
29                 public Expression Expr;
30                 public Attributes  OptAttributes;
31                 public FieldBuilder FieldBuilder;
32                 EmitContext const_ec;
33
34                 object ConstantValue = null;
35                 Type type;
36
37                 bool in_transit = false;
38
39                 public const int AllowedModifiers =
40                         Modifiers.NEW |
41                         Modifiers.PUBLIC |
42                         Modifiers.PROTECTED |
43                         Modifiers.INTERNAL |
44                         Modifiers.PRIVATE;
45
46                 public Const (Expression constant_type, string name, Expression expr, int mod_flags,
47                               Attributes attrs, Location loc)
48                         : base (name, loc)
49                 {
50                         ConstantType = constant_type;
51                         Name = name;
52                         Expr = expr;
53                         ModFlags = Modifiers.Check (AllowedModifiers, mod_flags, Modifiers.PRIVATE, loc);
54                         OptAttributes = attrs;
55                 }
56
57                 public FieldAttributes FieldAttr {
58                         get {
59                                 return FieldAttributes.Literal | FieldAttributes.Static |
60                                         Modifiers.FieldAttr (ModFlags) ;
61                         }
62                 }
63
64 #if DEBUG
65                 void dump_tree (Type t)
66                 {
67                         Console.WriteLine ("Dumping hierarchy");
68                         while (t != null){
69                                 Console.WriteLine ("   " + t.FullName + " " +
70                                         (t.GetType ().IsEnum ? "yes" : "no"));
71                                 t = t.BaseType;
72                         }
73                 }
74 #endif
75
76                 /// <summary>
77                 ///   Defines the constant in the @parent
78                 /// </summary>
79                 public override bool Define (TypeContainer parent)
80                 {
81                         type = parent.ResolveType (ConstantType, false, Location);
82
83                         if (type == null)
84                                 return false;
85
86                         const_ec = new EmitContext (parent, Location, null, type, ModFlags);
87                         
88                         if (!TypeManager.IsBuiltinType (type) &&
89                             (!type.IsSubclassOf (TypeManager.enum_type))) {
90                                 Report.Error (
91                                         -3, Location,
92                                         "Constant type is not valid (only system types are allowed)");
93                                 return false;
94                         }
95
96                         Type ptype = parent.TypeBuilder.BaseType;
97
98                         if (ptype != null) {
99                                 MemberList list = TypeContainer.FindMembers (
100                                         ptype, MemberTypes.Field, BindingFlags.Public,
101                                         Type.FilterName, Name);
102                                 
103                                 if (list.Count == 0)
104                                         if ((ModFlags & Modifiers.NEW) != 0)
105                                                 WarningNotHiding (parent);
106
107                         } else if ((ModFlags & Modifiers.NEW) != 0)
108                                 WarningNotHiding (parent);
109
110                         FieldBuilder = parent.TypeBuilder.DefineField (Name, type, FieldAttr);
111
112                         TypeManager.RegisterConstant (FieldBuilder, this);
113
114                         return true;
115                 }
116
117                 /// <summary>
118                 ///  Looks up the value of a constant field. Defines it if it hasn't
119                 ///  already been. Similar to LookupEnumValue in spirit.
120                 /// </summary>
121                 public object LookupConstantValue ()
122                 {
123                         if (ConstantValue != null)
124                                 return ConstantValue;
125
126                         if (in_transit) {
127                                 Report.Error (110, Location,
128                                               "The evaluation of the constant value for `" +
129                                               Name + "' involves a circular definition.");
130                                 return null;
131                         }
132
133                         in_transit = true;
134                         int errors = Report.Errors;
135
136                         Expr = Expr.Resolve (const_ec);
137
138                         in_transit = false;
139
140                         if (Expr == null) {
141                                 if (errors == Report.Errors)
142                                         Report.Error (150, Location, "A constant value is expected");
143                                 return null;
144                         }
145
146                         if (!(Expr is Constant)) {
147                                 UnCheckedExpr un_expr = Expr as UnCheckedExpr;
148                                 CheckedExpr ch_expr = Expr as CheckedExpr;
149
150                                 if ((un_expr != null) && (un_expr.Expr is Constant))
151                                         Expr = un_expr.Expr;
152                                 else if ((ch_expr != null) && (ch_expr.Expr is Constant))
153                                         Expr = ch_expr.Expr;
154                                 else {
155                                         if (errors == Report.Errors)
156                                                 Report.Error (150, Location, "A constant value is expected");
157                                         return null;
158                                 }
159                         }
160
161                         ConstantValue = ((Constant) Expr).GetValue ();
162
163                         if (type != Expr.Type) {
164                                 bool fail;
165
166                                 // from the null type to any reference-type.
167                                 if (Expr is NullLiteral && !type.IsValueType &&
168                                     !TypeManager.IsEnumType (type)){
169                                         return NullLiteral.Null;
170                                 }
171                                 
172                                 ConstantValue = TypeManager.ChangeType (ConstantValue, type, out fail);
173                                 if (fail){
174                                         Convert.Error_CannotImplicitConversion (Location, Expr.Type, type);
175                                         return null;
176                                 }
177
178                                 if (type == TypeManager.int32_type)
179                                         Expr = new IntConstant ((int) ConstantValue);
180                                 else if (type == TypeManager.uint32_type)
181                                         Expr = new UIntConstant ((uint) ConstantValue);
182                                 else if (type == TypeManager.int64_type)
183                                         Expr = new LongConstant ((long) ConstantValue);
184                                 else if (type == TypeManager.uint64_type)
185                                         Expr = new ULongConstant ((ulong) ConstantValue);
186                                 else if (type == TypeManager.float_type)
187                                         Expr = new FloatConstant ((float) ConstantValue);
188                                 else if (type == TypeManager.double_type)
189                                         Expr = new DoubleConstant ((double) ConstantValue);
190                                 else if (type == TypeManager.string_type)
191                                         Expr = new StringConstant ((string) ConstantValue);
192                                 else if (type == TypeManager.short_type)
193                                         Expr = new ShortConstant ((short) ConstantValue);
194                                 else if (type == TypeManager.ushort_type)
195                                         Expr = new UShortConstant ((ushort) ConstantValue);
196                                 else if (type == TypeManager.sbyte_type)
197                                         Expr = new SByteConstant ((sbyte) ConstantValue);
198                                 else if (type == TypeManager.byte_type)
199                                         Expr = new ByteConstant ((byte) ConstantValue);
200                                 else if (type == TypeManager.char_type)
201                                         Expr = new CharConstant ((char) ConstantValue);
202                                 else if (type == TypeManager.bool_type)
203                                         Expr = new BoolConstant ((bool) ConstantValue);
204                         }
205
206                         if (type.IsEnum){
207                                 //
208                                 // This sadly does not work for our user-defined enumerations types ;-(
209                                 //
210                                 try {
211                                         ConstantValue = System.Enum.ToObject (
212                                                 type, ConstantValue);
213                                 } catch (ArgumentException){
214                                         Report.Error (
215                                                 -16, Location,
216                                                 ".NET SDK 1.0 does not permit to create the constant "+
217                                                 " field from a user-defined enumeration");
218                                 }
219                         }
220
221                         FieldBuilder.SetConstant (ConstantValue);
222
223                         if (!TypeManager.RegisterFieldValue (FieldBuilder, ConstantValue))
224                                 return null;
225
226                         return ConstantValue;
227                 }
228                 
229                 
230                 /// <summary>
231                 ///  Emits the field value by evaluating the expression
232                 /// </summary>
233                 public void EmitConstant (TypeContainer parent)
234                 {
235                         LookupConstantValue ();
236                         
237                         return;
238                 }
239         }
240 }
241
242