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)
17 using MetaType = IKVM.Reflection.Type;
18 using IKVM.Reflection;
20 using MetaType = System.Type;
21 using System.Reflection;
24 namespace Mono.CSharp {
26 public class EnumMember : Const
28 class EnumTypeExpr : TypeExpr
30 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
32 type = ec.CurrentType;
36 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
38 return DoResolveAsTypeStep (ec);
42 public EnumMember (Enum parent, MemberName name, Attributes attrs)
43 : base (parent, new EnumTypeExpr (), Modifiers.PUBLIC, name, attrs)
47 static bool IsValidEnumType (TypeSpec t)
49 switch (t.BuildinType) {
50 case BuildinTypeSpec.Type.Int:
51 case BuildinTypeSpec.Type.UInt:
52 case BuildinTypeSpec.Type.Long:
53 case BuildinTypeSpec.Type.Byte:
54 case BuildinTypeSpec.Type.SByte:
55 case BuildinTypeSpec.Type.Short:
56 case BuildinTypeSpec.Type.UShort:
57 case BuildinTypeSpec.Type.ULong:
58 case BuildinTypeSpec.Type.Char:
65 public override Constant ConvertInitializer (ResolveContext rc, Constant expr)
67 if (expr is EnumConstant)
68 expr = ((EnumConstant) expr).Child;
70 var underlying = ((Enum) Parent).UnderlyingType;
72 expr = expr.ImplicitConversionRequired (rc, underlying, Location);
73 if (expr != null && !IsValidEnumType (expr.Type)) {
74 Enum.Error_1008 (Location, Report);
80 expr = New.Constantify (underlying, Location);
82 return new EnumConstant (expr, MemberType);
85 public override bool Define ()
87 if (!ResolveMemberType ())
90 const FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal;
91 FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType.GetMetaInfo (), attr);
92 spec = new ConstSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags, initializer);
94 Parent.MemberCache.AddMember (spec);
100 /// Enumeration container
102 public class Enum : TypeContainer
105 // Implicit enum member initializer, used when no constant value is provided
107 sealed class ImplicitInitializer : Expression
109 readonly EnumMember prev;
110 readonly EnumMember current;
112 public ImplicitInitializer (EnumMember current, EnumMember prev)
114 this.current = current;
118 public override Expression CreateExpressionTree (ResolveContext ec)
120 throw new NotSupportedException ("Missing Resolve call");
123 protected override Expression DoResolve (ResolveContext rc)
125 // We are the first member
127 return New.Constantify (current.Parent.Definition, Location);
130 var c = ((ConstSpec) prev.Spec).GetConstant (rc) as EnumConstant;
132 return c.Increment ();
133 } catch (OverflowException) {
134 rc.Report.Error (543, current.Location,
135 "The enumerator value `{0}' is outside the range of enumerator underlying type `{1}'",
136 current.GetSignatureForError (), ((Enum) current.Parent).UnderlyingType.GetSignatureForError ());
138 return New.Constantify (current.Parent.Definition, current.Location);
142 public override void Emit (EmitContext ec)
144 throw new NotSupportedException ("Missing Resolve call");
148 public static readonly string UnderlyingValueField = "value__";
150 const Modifiers AllowedModifiers =
153 Modifiers.PROTECTED |
157 public Enum (NamespaceEntry ns, DeclSpace parent, TypeExpression type,
158 Modifiers mod_flags, MemberName name, Attributes attrs)
159 : base (ns, parent, name, attrs, MemberKind.Enum)
161 base_type_expr = type;
162 var accmods = IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE;
163 ModFlags = ModifiersExtensions.Check (AllowedModifiers, mod_flags, accmods, Location, Report);
164 spec = new EnumSpec (null, this, null, null, ModFlags);
169 public override AttributeTargets AttributeTargets {
171 return AttributeTargets.Enum;
175 public TypeExpr BaseTypeExpression {
177 return base_type_expr;
181 protected override TypeAttributes TypeAttr {
183 return ModifiersExtensions.TypeAttr (ModFlags, IsTopLevel) |
184 TypeAttributes.Class | TypeAttributes.Sealed | base.TypeAttr;
188 public TypeSpec UnderlyingType {
190 return ((EnumSpec) spec).UnderlyingType;
196 public override void Accept (StructuralVisitor visitor)
198 visitor.Visit (this);
201 public void AddEnumMember (EnumMember em)
203 if (em.Name == UnderlyingValueField) {
204 Report.Error (76, em.Location, "An item in an enumeration cannot have an identifier `{0}'",
205 UnderlyingValueField);
212 public static void Error_1008 (Location loc, Report Report)
214 Report.Error (1008, loc,
215 "Type byte, sbyte, short, ushort, int, uint, long or ulong expected");
218 protected override bool DefineNestedTypes ()
220 ((EnumSpec) spec).UnderlyingType = base_type_expr == null ? Compiler.BuildinTypes.Int : base_type_expr.Type;
222 TypeBuilder.DefineField (UnderlyingValueField, UnderlyingType.GetMetaInfo (),
223 FieldAttributes.Public | FieldAttributes.SpecialName | FieldAttributes.RTSpecialName);
228 protected override bool DoDefineMembers ()
230 if (constants != null) {
231 for (int i = 0; i < constants.Count; ++i) {
232 EnumMember em = (EnumMember) constants [i];
233 if (em.Initializer == null) {
234 em.Initializer = new ImplicitInitializer (em, i == 0 ? null : (EnumMember) constants[i - 1]);
244 public override bool IsUnmanagedType ()
249 protected override TypeExpr[] ResolveBaseTypes (out TypeExpr base_class)
251 base_type = Compiler.BuildinTypes.Enum;
252 base_class = base_type_expr;
256 protected override bool VerifyClsCompliance ()
258 if (!base.VerifyClsCompliance ())
261 switch (UnderlyingType.BuildinType) {
262 case BuildinTypeSpec.Type.UInt:
263 case BuildinTypeSpec.Type.ULong:
264 case BuildinTypeSpec.Type.UShort:
265 Report.Warning (3009, 1, Location, "`{0}': base type `{1}' is not CLS-compliant",
266 GetSignatureForError (), TypeManager.CSharpName (UnderlyingType));
274 class EnumSpec : TypeSpec
278 public EnumSpec (TypeSpec declaringType, ITypeDefinition definition, TypeSpec underlyingType, MetaType info, Modifiers modifiers)
279 : base (MemberKind.Enum, declaringType, definition, info, modifiers | Modifiers.SEALED)
281 this.underlying = underlyingType;
284 public TypeSpec UnderlyingType {
289 if (underlying != null)
290 throw new InternalErrorException ("UnderlyingType reset");
296 public static TypeSpec GetUnderlyingType (TypeSpec t)
298 return ((EnumSpec) t.GetDefinition ()).UnderlyingType;
301 public static bool IsValidUnderlyingType (TypeSpec type)
303 switch (type.BuildinType) {
304 case BuildinTypeSpec.Type.Int:
305 case BuildinTypeSpec.Type.UInt:
306 case BuildinTypeSpec.Type.Long:
307 case BuildinTypeSpec.Type.Byte:
308 case BuildinTypeSpec.Type.SByte:
309 case BuildinTypeSpec.Type.Short:
310 case BuildinTypeSpec.Type.UShort:
311 case BuildinTypeSpec.Type.ULong: