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;
28 public class EnumMember : Const
31 class MemberTypeDelegator : TypeDelegator
35 public MemberTypeDelegator (Type delegatingType, Type underlyingType)
36 : base (delegatingType)
38 this.underlyingType = underlyingType;
41 public override Type GetEnumUnderlyingType ()
43 return underlyingType;
48 class EnumTypeExpr : TypeExpr
50 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
52 type = ec.CurrentType;
53 eclass = ExprClass.Type;
58 public EnumMember (Enum parent, MemberName name, Attributes attrs)
59 : base (parent, new EnumTypeExpr (), Modifiers.PUBLIC, name, attrs)
63 static bool IsValidEnumType (TypeSpec t)
65 switch (t.BuiltinType) {
66 case BuiltinTypeSpec.Type.Int:
67 case BuiltinTypeSpec.Type.UInt:
68 case BuiltinTypeSpec.Type.Long:
69 case BuiltinTypeSpec.Type.Byte:
70 case BuiltinTypeSpec.Type.SByte:
71 case BuiltinTypeSpec.Type.Short:
72 case BuiltinTypeSpec.Type.UShort:
73 case BuiltinTypeSpec.Type.ULong:
74 case BuiltinTypeSpec.Type.Char:
81 public override Constant ConvertInitializer (ResolveContext rc, Constant expr)
83 if (expr is EnumConstant)
84 expr = ((EnumConstant) expr).Child;
86 var en = (Enum)Parent;
87 var underlying = en.UnderlyingType;
89 expr = expr.ImplicitConversionRequired (rc, underlying);
90 if (expr != null && !IsValidEnumType (expr.Type)) {
91 en.Error_UnderlyingType (Location);
97 expr = New.Constantify (underlying, Location);
99 return new EnumConstant (expr, MemberType);
102 public override bool Define ()
104 if (!ResolveMemberType ())
107 MetaType ftype = MemberType.GetMetaInfo ();
110 // Workaround for .net SRE limitation which cannot define field of unbaked enum type
111 // which is how all enums are declared
113 ftype = new MemberTypeDelegator (ftype, ((Enum)Parent).UnderlyingType.GetMetaInfo ());
116 const FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal;
117 FieldBuilder = Parent.TypeBuilder.DefineField (Name, ftype, attr);
118 spec = new ConstSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags, initializer);
120 Parent.MemberCache.AddMember (spec);
124 public override void Accept (StructuralVisitor visitor)
126 visitor.Visit (this);
132 /// Enumeration container
134 public class Enum : TypeDefinition
137 // Implicit enum member initializer, used when no constant value is provided
139 sealed class ImplicitInitializer : Expression
141 readonly EnumMember prev;
142 readonly EnumMember current;
144 public ImplicitInitializer (EnumMember current, EnumMember prev)
146 this.current = current;
150 public override bool ContainsEmitWithAwait ()
155 public override Expression CreateExpressionTree (ResolveContext ec)
157 throw new NotSupportedException ("Missing Resolve call");
160 protected override Expression DoResolve (ResolveContext rc)
162 // We are the first member
164 return New.Constantify (current.Parent.Definition, Location);
167 var c = ((ConstSpec) prev.Spec).GetConstant (rc) as EnumConstant;
169 return c.Increment ();
170 } catch (OverflowException) {
171 rc.Report.Error (543, current.Location,
172 "The enumerator value `{0}' is outside the range of enumerator underlying type `{1}'",
173 current.GetSignatureForError (), ((Enum) current.Parent).UnderlyingType.GetSignatureForError ());
175 return New.Constantify (current.Parent.Definition, current.Location);
179 public override void Emit (EmitContext ec)
181 throw new NotSupportedException ("Missing Resolve call");
185 public static readonly string UnderlyingValueField = "value__";
187 const Modifiers AllowedModifiers =
190 Modifiers.PROTECTED |
194 readonly FullNamedExpression underlying_type_expr;
196 public Enum (TypeContainer parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs)
197 : base (parent, name, attrs, MemberKind.Enum)
199 underlying_type_expr = type;
200 var accmods = IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE;
201 ModFlags = ModifiersExtensions.Check (AllowedModifiers, mod_flags, accmods, Location, Report);
202 spec = new EnumSpec (null, this, null, null, ModFlags);
207 public override AttributeTargets AttributeTargets {
209 return AttributeTargets.Enum;
213 public FullNamedExpression BaseTypeExpression {
215 return underlying_type_expr;
219 protected override TypeAttributes TypeAttr {
221 return base.TypeAttr | TypeAttributes.Class | TypeAttributes.Sealed;
225 public TypeSpec UnderlyingType {
227 return ((EnumSpec) spec).UnderlyingType;
233 public override void Accept (StructuralVisitor visitor)
235 visitor.Visit (this);
238 public void AddEnumMember (EnumMember em)
240 if (em.Name == UnderlyingValueField) {
241 Report.Error (76, em.Location, "An item in an enumeration cannot have an identifier `{0}'",
242 UnderlyingValueField);
249 public void Error_UnderlyingType (Location loc)
251 Report.Error (1008, loc,
252 "Type byte, sbyte, short, ushort, int, uint, long or ulong expected");
255 protected override void DoDefineContainer ()
258 if (underlying_type_expr != null) {
259 ut = underlying_type_expr.ResolveAsType (this);
260 if (!EnumSpec.IsValidUnderlyingType (ut)) {
261 Error_UnderlyingType (underlying_type_expr.Location);
269 ut = Compiler.BuiltinTypes.Int;
271 ((EnumSpec) spec).UnderlyingType = ut;
273 TypeBuilder.DefineField (UnderlyingValueField, UnderlyingType.GetMetaInfo (),
274 FieldAttributes.Public | FieldAttributes.SpecialName | FieldAttributes.RTSpecialName);
279 protected override bool DoDefineMembers ()
281 for (int i = 0; i < Members.Count; ++i) {
282 EnumMember em = (EnumMember) Members[i];
283 if (em.Initializer == null) {
284 em.Initializer = new ImplicitInitializer (em, i == 0 ? null : (EnumMember) Members[i - 1]);
293 public override bool IsUnmanagedType ()
298 protected override TypeSpec[] ResolveBaseTypes (out FullNamedExpression base_class)
300 base_type = Compiler.BuiltinTypes.Enum;
305 protected override bool VerifyClsCompliance ()
307 if (!base.VerifyClsCompliance ())
310 switch (UnderlyingType.BuiltinType) {
311 case BuiltinTypeSpec.Type.UInt:
312 case BuiltinTypeSpec.Type.ULong:
313 case BuiltinTypeSpec.Type.UShort:
314 Report.Warning (3009, 1, Location, "`{0}': base type `{1}' is not CLS-compliant",
315 GetSignatureForError (), UnderlyingType.GetSignatureForError ());
323 class EnumSpec : TypeSpec
327 public EnumSpec (TypeSpec declaringType, ITypeDefinition definition, TypeSpec underlyingType, MetaType info, Modifiers modifiers)
328 : base (MemberKind.Enum, declaringType, definition, info, modifiers | Modifiers.SEALED)
330 this.underlying = underlyingType;
333 public TypeSpec UnderlyingType {
338 if (underlying != null)
339 throw new InternalErrorException ("UnderlyingType reset");
345 public static TypeSpec GetUnderlyingType (TypeSpec t)
347 return ((EnumSpec) t.GetDefinition ()).UnderlyingType;
350 public static bool IsValidUnderlyingType (TypeSpec type)
352 switch (type.BuiltinType) {
353 case BuiltinTypeSpec.Type.Int:
354 case BuiltinTypeSpec.Type.UInt:
355 case BuiltinTypeSpec.Type.Long:
356 case BuiltinTypeSpec.Type.Byte:
357 case BuiltinTypeSpec.Type.SByte:
358 case BuiltinTypeSpec.Type.Short:
359 case BuiltinTypeSpec.Type.UShort:
360 case BuiltinTypeSpec.Type.ULong: