Merge pull request #93 from konrad-kruczynski/dispatcher_timer_fix
[mono.git] / mcs / mcs / enum.cs
1 //
2 // enum.cs: Enum handling.
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //         Ravi Pratap     (ravi@ximian.com)
6 //         Marek Safar     (marek.safar@seznam.cz)
7 //
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 //
10 // Copyright 2001 Ximian, Inc (http://www.ximian.com)
11 // Copyright 2003-2003 Novell, Inc (http://www.novell.com)
12 //
13
14 using System;
15
16 #if STATIC
17 using MetaType = IKVM.Reflection.Type;
18 using IKVM.Reflection;
19 #else
20 using MetaType = System.Type;
21 using System.Reflection;
22 #endif
23
24 namespace Mono.CSharp {
25
26         public class EnumMember : Const
27         {
28                 class EnumTypeExpr : TypeExpr
29                 {
30                         public override TypeSpec ResolveAsType (IMemberContext ec)
31                         {
32                                 type = ec.CurrentType;
33                                 eclass = ExprClass.Type;
34                                 return type;
35                         }
36                 }
37
38                 public EnumMember (Enum parent, MemberName name, Attributes attrs)
39                         : base (parent, new EnumTypeExpr (), Modifiers.PUBLIC, name, attrs)
40                 {
41                 }
42
43                 static bool IsValidEnumType (TypeSpec t)
44                 {
45                         switch (t.BuiltinType) {
46                         case BuiltinTypeSpec.Type.Int:
47                         case BuiltinTypeSpec.Type.UInt:
48                         case BuiltinTypeSpec.Type.Long:
49                         case BuiltinTypeSpec.Type.Byte:
50                         case BuiltinTypeSpec.Type.SByte:
51                         case BuiltinTypeSpec.Type.Short:
52                         case BuiltinTypeSpec.Type.UShort:
53                         case BuiltinTypeSpec.Type.ULong:
54                         case BuiltinTypeSpec.Type.Char:
55                                 return true;
56                         default:
57                                 return t.IsEnum;
58                         }
59                 }
60
61                 public override Constant ConvertInitializer (ResolveContext rc, Constant expr)
62                 {
63                         if (expr is EnumConstant)
64                                 expr = ((EnumConstant) expr).Child;
65
66                         var underlying = ((Enum) Parent).UnderlyingType;
67                         if (expr != null) {
68                                 expr = expr.ImplicitConversionRequired (rc, underlying, Location);
69                                 if (expr != null && !IsValidEnumType (expr.Type)) {
70                                         Enum.Error_1008 (Location, Report);
71                                         expr = null;
72                                 }
73                         }
74
75                         if (expr == null)
76                                 expr = New.Constantify (underlying, Location);
77
78                         return new EnumConstant (expr, MemberType);
79                 }
80
81                 public override bool Define ()
82                 {
83                         if (!ResolveMemberType ())
84                                 return false;
85
86                         const FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal;
87                         FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType.GetMetaInfo (), attr);
88                         spec = new ConstSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags, initializer);
89
90                         Parent.MemberCache.AddMember (spec);
91                         return true;
92                 }
93         }
94
95         /// <summary>
96         ///   Enumeration container
97         /// </summary>
98         public class Enum : TypeContainer
99         {
100                 //
101                 // Implicit enum member initializer, used when no constant value is provided
102                 //
103                 sealed class ImplicitInitializer : Expression
104                 {
105                         readonly EnumMember prev;
106                         readonly EnumMember current;
107
108                         public ImplicitInitializer (EnumMember current, EnumMember prev)
109                         {
110                                 this.current = current;
111                                 this.prev = prev;
112                         }
113
114                         public override bool ContainsEmitWithAwait ()
115                         {
116                                 return false;
117                         }
118
119                         public override Expression CreateExpressionTree (ResolveContext ec)
120                         {
121                                 throw new NotSupportedException ("Missing Resolve call");
122                         }
123
124                         protected override Expression DoResolve (ResolveContext rc)
125                         {
126                                 // We are the first member
127                                 if (prev == null) {
128                                         return New.Constantify (current.Parent.Definition, Location);
129                                 }
130
131                                 var c = ((ConstSpec) prev.Spec).GetConstant (rc) as EnumConstant;
132                                 try {
133                                         return c.Increment ();
134                                 } catch (OverflowException) {
135                                         rc.Report.Error (543, current.Location,
136                                                 "The enumerator value `{0}' is outside the range of enumerator underlying type `{1}'",
137                                                 current.GetSignatureForError (), ((Enum) current.Parent).UnderlyingType.GetSignatureForError ());
138
139                                         return New.Constantify (current.Parent.Definition, current.Location);
140                                 }
141                         }
142
143                         public override void Emit (EmitContext ec)
144                         {
145                                 throw new NotSupportedException ("Missing Resolve call");
146                         }
147                 }
148
149                 public static readonly string UnderlyingValueField = "value__";
150
151                 const Modifiers AllowedModifiers =
152                         Modifiers.NEW |
153                         Modifiers.PUBLIC |
154                         Modifiers.PROTECTED |
155                         Modifiers.INTERNAL |
156                         Modifiers.PRIVATE;
157
158                 readonly TypeExpr underlying_type_expr;
159
160                 public Enum (NamespaceContainer ns, DeclSpace parent, TypeExpression type,
161                              Modifiers mod_flags, MemberName name, Attributes attrs)
162                         : base (ns, parent, name, attrs, MemberKind.Enum)
163                 {
164                         underlying_type_expr = type;
165                         var accmods = IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE;
166                         ModFlags = ModifiersExtensions.Check (AllowedModifiers, mod_flags, accmods, Location, Report);
167                         spec = new EnumSpec (null, this, null, null, ModFlags);
168                 }
169
170                 #region Properties
171
172                 public override AttributeTargets AttributeTargets {
173                         get {
174                                 return AttributeTargets.Enum;
175                         }
176                 }
177
178                 public TypeExpr BaseTypeExpression {
179                         get {
180                                 return underlying_type_expr;
181                         }
182                 }
183
184                 protected override TypeAttributes TypeAttr {
185                         get {
186                                 return ModifiersExtensions.TypeAttr (ModFlags, IsTopLevel) |
187                                         TypeAttributes.Class | TypeAttributes.Sealed | base.TypeAttr;
188                         }
189                 }
190
191                 public TypeSpec UnderlyingType {
192                         get {
193                                 return ((EnumSpec) spec).UnderlyingType;
194                         }
195                 }
196
197                 #endregion
198
199                 public override void Accept (StructuralVisitor visitor)
200                 {
201                         visitor.Visit (this);
202                 }
203
204                 public void AddEnumMember (EnumMember em)
205                 {
206                         if (em.Name == UnderlyingValueField) {
207                                 Report.Error (76, em.Location, "An item in an enumeration cannot have an identifier `{0}'",
208                                         UnderlyingValueField);
209                                 return;
210                         }
211
212                         AddConstant (em);
213                 }
214
215                 public static void Error_1008 (Location loc, Report Report)
216                 {
217                         Report.Error (1008, loc,
218                                 "Type byte, sbyte, short, ushort, int, uint, long or ulong expected");
219                 }
220
221                 protected override bool DefineNestedTypes ()
222                 {
223                         ((EnumSpec) spec).UnderlyingType = underlying_type_expr == null ? Compiler.BuiltinTypes.Int : underlying_type_expr.Type;
224
225                         TypeBuilder.DefineField (UnderlyingValueField, UnderlyingType.GetMetaInfo (),
226                                 FieldAttributes.Public | FieldAttributes.SpecialName | FieldAttributes.RTSpecialName);
227
228                         return true;
229                 }
230
231                 protected override bool DoDefineMembers ()
232                 {
233                         if (constants != null) {
234                                 for (int i = 0; i < constants.Count; ++i) {
235                                         EnumMember em = (EnumMember) constants [i];
236                                         if (em.Initializer == null) {
237                                                 em.Initializer = new ImplicitInitializer (em, i == 0 ? null : (EnumMember) constants[i - 1]);
238                                         }
239
240                                         em.Define ();
241                                 }
242                         }
243
244                         return true;
245                 }
246
247                 public override bool IsUnmanagedType ()
248                 {
249                         return true;
250                 }
251
252                 protected override TypeSpec[] ResolveBaseTypes (out FullNamedExpression base_class)
253                 {
254                         base_type = Compiler.BuiltinTypes.Enum;
255                         base_class = null;
256                         return null;
257                 }
258
259                 protected override bool VerifyClsCompliance ()
260                 {
261                         if (!base.VerifyClsCompliance ())
262                                 return false;
263
264                         switch (UnderlyingType.BuiltinType) {
265                         case BuiltinTypeSpec.Type.UInt:
266                         case BuiltinTypeSpec.Type.ULong:
267                         case BuiltinTypeSpec.Type.UShort:
268                                 Report.Warning (3009, 1, Location, "`{0}': base type `{1}' is not CLS-compliant",
269                                         GetSignatureForError (), TypeManager.CSharpName (UnderlyingType));
270                                 break;
271                         }
272
273                         return true;
274                 }       
275         }
276
277         class EnumSpec : TypeSpec
278         {
279                 TypeSpec underlying;
280
281                 public EnumSpec (TypeSpec declaringType, ITypeDefinition definition, TypeSpec underlyingType, MetaType info, Modifiers modifiers)
282                         : base (MemberKind.Enum, declaringType, definition, info, modifiers | Modifiers.SEALED)
283                 {
284                         this.underlying = underlyingType;
285                 }
286
287                 public TypeSpec UnderlyingType {
288                         get {
289                                 return underlying;
290                         }
291                         set {
292                                 if (underlying != null)
293                                         throw new InternalErrorException ("UnderlyingType reset");
294
295                                 underlying = value;
296                         }
297                 }
298
299                 public static TypeSpec GetUnderlyingType (TypeSpec t)
300                 {
301                         return ((EnumSpec) t.GetDefinition ()).UnderlyingType;
302                 }
303
304                 public static bool IsValidUnderlyingType (TypeSpec type)
305                 {
306                         switch (type.BuiltinType) {
307                         case BuiltinTypeSpec.Type.Int:
308                         case BuiltinTypeSpec.Type.UInt:
309                         case BuiltinTypeSpec.Type.Long:
310                         case BuiltinTypeSpec.Type.Byte:
311                         case BuiltinTypeSpec.Type.SByte:
312                         case BuiltinTypeSpec.Type.Short:
313                         case BuiltinTypeSpec.Type.UShort:
314                         case BuiltinTypeSpec.Type.ULong:
315                                 return true;
316                         }
317
318                         return false;
319                 }
320         }
321 }