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