2 // enum.cs: Enum handling.
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 // Ravi Pratap (ravi@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
10 // Copyright 2001 Ximian, Inc (http://www.ximian.com)
11 // Copyright 2003-2003 Novell, Inc (http://www.novell.com)
12 // Copyright 2011 Xamarin Inc
18 using MetaType = IKVM.Reflection.Type;
19 using IKVM.Reflection;
21 using MetaType = System.Type;
22 using System.Reflection;
25 namespace Mono.CSharp {
27 public class EnumMember : Const
29 class EnumTypeExpr : TypeExpr
31 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
33 type = ec.CurrentType;
34 eclass = ExprClass.Type;
39 public EnumMember (Enum parent, MemberName name, Attributes attrs)
40 : base (parent, new EnumTypeExpr (), Modifiers.PUBLIC, name, attrs)
44 static bool IsValidEnumType (TypeSpec t)
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:
62 public override Constant ConvertInitializer (ResolveContext rc, Constant expr)
64 if (expr is EnumConstant)
65 expr = ((EnumConstant) expr).Child;
67 var en = (Enum)Parent;
68 var underlying = en.UnderlyingType;
70 expr = expr.ImplicitConversionRequired (rc, underlying);
71 if (expr != null && !IsValidEnumType (expr.Type)) {
72 en.Error_UnderlyingType (Location);
78 expr = New.Constantify (underlying, Location);
80 return new EnumConstant (expr, MemberType);
83 public override bool Define ()
85 if (!ResolveMemberType ())
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);
92 Parent.MemberCache.AddMember (spec);
96 public override void Accept (StructuralVisitor visitor)
104 /// Enumeration container
106 public class Enum : TypeDefinition
109 // Implicit enum member initializer, used when no constant value is provided
111 sealed class ImplicitInitializer : Expression
113 readonly EnumMember prev;
114 readonly EnumMember current;
116 public ImplicitInitializer (EnumMember current, EnumMember prev)
118 this.current = current;
122 public override bool ContainsEmitWithAwait ()
127 public override Expression CreateExpressionTree (ResolveContext ec)
129 throw new NotSupportedException ("Missing Resolve call");
132 protected override Expression DoResolve (ResolveContext rc)
134 // We are the first member
136 return New.Constantify (current.Parent.Definition, Location);
139 var c = ((ConstSpec) prev.Spec).GetConstant (rc) as EnumConstant;
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 ());
147 return New.Constantify (current.Parent.Definition, current.Location);
151 public override void Emit (EmitContext ec)
153 throw new NotSupportedException ("Missing Resolve call");
157 public static readonly string UnderlyingValueField = "value__";
159 const Modifiers AllowedModifiers =
162 Modifiers.PROTECTED |
166 readonly FullNamedExpression underlying_type_expr;
168 public Enum (TypeContainer parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs)
169 : base (parent, name, attrs, MemberKind.Enum)
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);
179 public override AttributeTargets AttributeTargets {
181 return AttributeTargets.Enum;
185 public FullNamedExpression BaseTypeExpression {
187 return underlying_type_expr;
191 protected override TypeAttributes TypeAttr {
193 return base.TypeAttr | TypeAttributes.Class | TypeAttributes.Sealed;
197 public TypeSpec UnderlyingType {
199 return ((EnumSpec) spec).UnderlyingType;
205 public override void Accept (StructuralVisitor visitor)
207 visitor.Visit (this);
210 public void AddEnumMember (EnumMember em)
212 if (em.Name == UnderlyingValueField) {
213 Report.Error (76, em.Location, "An item in an enumeration cannot have an identifier `{0}'",
214 UnderlyingValueField);
221 public void Error_UnderlyingType (Location loc)
223 Report.Error (1008, loc,
224 "Type byte, sbyte, short, ushort, int, uint, long or ulong expected");
227 protected override void DoDefineContainer ()
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);
241 ut = Compiler.BuiltinTypes.Int;
243 ((EnumSpec) spec).UnderlyingType = ut;
245 TypeBuilder.DefineField (UnderlyingValueField, UnderlyingType.GetMetaInfo (),
246 FieldAttributes.Public | FieldAttributes.SpecialName | FieldAttributes.RTSpecialName);
251 protected override bool DoDefineMembers ()
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]);
265 public override bool IsUnmanagedType ()
270 protected override TypeSpec[] ResolveBaseTypes (out FullNamedExpression base_class)
272 base_type = Compiler.BuiltinTypes.Enum;
277 protected override bool VerifyClsCompliance ()
279 if (!base.VerifyClsCompliance ())
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 ());
295 class EnumSpec : TypeSpec
299 public EnumSpec (TypeSpec declaringType, ITypeDefinition definition, TypeSpec underlyingType, MetaType info, Modifiers modifiers)
300 : base (MemberKind.Enum, declaringType, definition, info, modifiers | Modifiers.SEALED)
302 this.underlying = underlyingType;
305 public TypeSpec UnderlyingType {
310 if (underlying != null)
311 throw new InternalErrorException ("UnderlyingType reset");
317 public static TypeSpec GetUnderlyingType (TypeSpec t)
319 return ((EnumSpec) t.GetDefinition ()).UnderlyingType;
322 public static bool IsValidUnderlyingType (TypeSpec type)
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: