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