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