Rework top-level type AST hierarchy to include namespaces. Allows MD to iterate full...
[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)
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 underlying = ((Enum) Parent).UnderlyingType;
68                         if (expr != null) {
69                                 expr = expr.ImplicitConversionRequired (rc, underlying, Location);
70                                 if (expr != null && !IsValidEnumType (expr.Type)) {
71                                         Enum.Error_1008 (Location, Report);
72                                         expr = null;
73                                 }
74                         }
75
76                         if (expr == null)
77                                 expr = New.Constantify (underlying, Location);
78
79                         return new EnumConstant (expr, MemberType);
80                 }
81
82                 public override bool Define ()
83                 {
84                         if (!ResolveMemberType ())
85                                 return false;
86
87                         const FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal;
88                         FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType.GetMetaInfo (), attr);
89                         spec = new ConstSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags, initializer);
90
91                         Parent.MemberCache.AddMember (spec);
92                         return true;
93                 }
94                 
95                 public override void Accept (StructuralVisitor visitor)
96                 {
97                         visitor.Visit (this);
98                 }
99
100         }
101
102         /// <summary>
103         ///   Enumeration container
104         /// </summary>
105         public class Enum : TypeDefinition
106         {
107                 //
108                 // Implicit enum member initializer, used when no constant value is provided
109                 //
110                 sealed class ImplicitInitializer : Expression
111                 {
112                         readonly EnumMember prev;
113                         readonly EnumMember current;
114
115                         public ImplicitInitializer (EnumMember current, EnumMember prev)
116                         {
117                                 this.current = current;
118                                 this.prev = prev;
119                         }
120
121                         public override bool ContainsEmitWithAwait ()
122                         {
123                                 return false;
124                         }
125
126                         public override Expression CreateExpressionTree (ResolveContext ec)
127                         {
128                                 throw new NotSupportedException ("Missing Resolve call");
129                         }
130
131                         protected override Expression DoResolve (ResolveContext rc)
132                         {
133                                 // We are the first member
134                                 if (prev == null) {
135                                         return New.Constantify (current.Parent.Definition, Location);
136                                 }
137
138                                 var c = ((ConstSpec) prev.Spec).GetConstant (rc) as EnumConstant;
139                                 try {
140                                         return c.Increment ();
141                                 } catch (OverflowException) {
142                                         rc.Report.Error (543, current.Location,
143                                                 "The enumerator value `{0}' is outside the range of enumerator underlying type `{1}'",
144                                                 current.GetSignatureForError (), ((Enum) current.Parent).UnderlyingType.GetSignatureForError ());
145
146                                         return New.Constantify (current.Parent.Definition, current.Location);
147                                 }
148                         }
149
150                         public override void Emit (EmitContext ec)
151                         {
152                                 throw new NotSupportedException ("Missing Resolve call");
153                         }
154                 }
155
156                 public static readonly string UnderlyingValueField = "value__";
157
158                 const Modifiers AllowedModifiers =
159                         Modifiers.NEW |
160                         Modifiers.PUBLIC |
161                         Modifiers.PROTECTED |
162                         Modifiers.INTERNAL |
163                         Modifiers.PRIVATE;
164
165                 readonly TypeExpr underlying_type_expr;
166
167                 public Enum (TypeContainer parent, TypeExpression type, Modifiers mod_flags, MemberName name, Attributes attrs)
168                         : base (parent, name, attrs, MemberKind.Enum)
169                 {
170                         underlying_type_expr = type;
171                         var accmods = IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE;
172                         ModFlags = ModifiersExtensions.Check (AllowedModifiers, mod_flags, accmods, Location, Report);
173                         spec = new EnumSpec (null, this, null, null, ModFlags);
174                 }
175
176                 #region Properties
177
178                 public override AttributeTargets AttributeTargets {
179                         get {
180                                 return AttributeTargets.Enum;
181                         }
182                 }
183
184                 public TypeExpr BaseTypeExpression {
185                         get {
186                                 return underlying_type_expr;
187                         }
188                 }
189
190                 protected override TypeAttributes TypeAttr {
191                         get {
192                                 return ModifiersExtensions.TypeAttr (ModFlags, IsTopLevel) |
193                                         TypeAttributes.Class | TypeAttributes.Sealed | base.TypeAttr;
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                         AddConstant (em);
219                 }
220
221                 public static void Error_1008 (Location loc, Report Report)
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                         ((EnumSpec) spec).UnderlyingType = underlying_type_expr == null ? Compiler.BuiltinTypes.Int : underlying_type_expr.Type;
230
231                         TypeBuilder.DefineField (UnderlyingValueField, UnderlyingType.GetMetaInfo (),
232                                 FieldAttributes.Public | FieldAttributes.SpecialName | FieldAttributes.RTSpecialName);
233
234                         DefineBaseTypes ();
235                 }
236
237                 protected override bool DoDefineMembers ()
238                 {
239                         if (constants != null) {
240                                 for (int i = 0; i < constants.Count; ++i) {
241                                         EnumMember em = (EnumMember) constants [i];
242                                         if (em.Initializer == null) {
243                                                 em.Initializer = new ImplicitInitializer (em, i == 0 ? null : (EnumMember) constants[i - 1]);
244                                         }
245
246                                         em.Define ();
247                                 }
248                         }
249
250                         return true;
251                 }
252
253                 public override bool IsUnmanagedType ()
254                 {
255                         return true;
256                 }
257
258                 protected override TypeSpec[] ResolveBaseTypes (out FullNamedExpression base_class)
259                 {
260                         base_type = Compiler.BuiltinTypes.Enum;
261                         base_class = null;
262                         return null;
263                 }
264
265                 protected override bool VerifyClsCompliance ()
266                 {
267                         if (!base.VerifyClsCompliance ())
268                                 return false;
269
270                         switch (UnderlyingType.BuiltinType) {
271                         case BuiltinTypeSpec.Type.UInt:
272                         case BuiltinTypeSpec.Type.ULong:
273                         case BuiltinTypeSpec.Type.UShort:
274                                 Report.Warning (3009, 1, Location, "`{0}': base type `{1}' is not CLS-compliant",
275                                         GetSignatureForError (), TypeManager.CSharpName (UnderlyingType));
276                                 break;
277                         }
278
279                         return true;
280                 }       
281         }
282
283         class EnumSpec : TypeSpec
284         {
285                 TypeSpec underlying;
286
287                 public EnumSpec (TypeSpec declaringType, ITypeDefinition definition, TypeSpec underlyingType, MetaType info, Modifiers modifiers)
288                         : base (MemberKind.Enum, declaringType, definition, info, modifiers | Modifiers.SEALED)
289                 {
290                         this.underlying = underlyingType;
291                 }
292
293                 public TypeSpec UnderlyingType {
294                         get {
295                                 return underlying;
296                         }
297                         set {
298                                 if (underlying != null)
299                                         throw new InternalErrorException ("UnderlyingType reset");
300
301                                 underlying = value;
302                         }
303                 }
304
305                 public static TypeSpec GetUnderlyingType (TypeSpec t)
306                 {
307                         return ((EnumSpec) t.GetDefinition ()).UnderlyingType;
308                 }
309
310                 public static bool IsValidUnderlyingType (TypeSpec type)
311                 {
312                         switch (type.BuiltinType) {
313                         case BuiltinTypeSpec.Type.Int:
314                         case BuiltinTypeSpec.Type.UInt:
315                         case BuiltinTypeSpec.Type.Long:
316                         case BuiltinTypeSpec.Type.Byte:
317                         case BuiltinTypeSpec.Type.SByte:
318                         case BuiltinTypeSpec.Type.Short:
319                         case BuiltinTypeSpec.Type.UShort:
320                         case BuiltinTypeSpec.Type.ULong:
321                                 return true;
322                         }
323
324                         return false;
325                 }
326         }
327 }