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