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)
15 using System.Collections.Generic;
16 using System.Reflection;
17 using System.Reflection.Emit;
18 using System.Globalization;
20 namespace Mono.CSharp {
22 public class EnumMember : Const
24 class EnumTypeExpr : TypeExpr
26 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
28 type = ec.CurrentType;
32 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
34 return DoResolveAsTypeStep (ec);
38 public EnumMember (Enum parent, MemberName name, Attributes attrs)
39 : base (parent, new EnumTypeExpr (), Modifiers.PUBLIC, name, attrs)
43 static bool IsValidEnumType (TypeSpec t)
45 return (t == TypeManager.int32_type || t == TypeManager.uint32_type || t == TypeManager.int64_type ||
46 t == TypeManager.byte_type || t == TypeManager.sbyte_type || t == TypeManager.short_type ||
47 t == TypeManager.ushort_type || t == TypeManager.uint64_type || t == TypeManager.char_type ||
48 TypeManager.IsEnumType (t));
51 public override Constant ConvertInitializer (ResolveContext rc, Constant expr)
53 if (expr is EnumConstant)
54 expr = ((EnumConstant) expr).Child;
56 var underlying = ((Enum) Parent).UnderlyingType;
58 expr = expr.ImplicitConversionRequired (rc, underlying, Location);
59 if (expr != null && !IsValidEnumType (expr.Type)) {
60 Enum.Error_1008 (Location, Report);
66 expr = New.Constantify (underlying, Location);
68 return new EnumConstant (expr, MemberType).Resolve (rc);
71 public override bool Define ()
73 if (!ResolveMemberType ())
76 const FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal;
77 FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType.GetMetaInfo (), attr);
78 spec = new ConstSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags, initializer);
80 Parent.MemberCache.AddMember (spec);
86 /// Enumeration container
88 public class Enum : TypeContainer
91 // Implicit enum member initializer, used when no constant value is provided
93 class ImplicitInitializer : Expression
95 readonly EnumMember prev;
96 readonly EnumMember current;
98 public ImplicitInitializer (EnumMember current, EnumMember prev)
100 this.current = current;
104 public override Expression CreateExpressionTree (ResolveContext ec)
106 throw new NotSupportedException ("Missing Resolve call");
109 protected override Expression DoResolve (ResolveContext rc)
111 // We are the first member
113 return New.Constantify (current.Parent.Definition, Location).Resolve (rc);
116 var c = ((ConstSpec) prev.Spec).GetConstant (rc) as EnumConstant;
118 return c.Increment ().Resolve (rc);
119 } catch (OverflowException) {
120 rc.Report.Error (543, current.Location,
121 "The enumerator value `{0}' is outside the range of enumerator underlying type `{1}'",
122 current.GetSignatureForError (), ((Enum) current.Parent).UnderlyingType.GetSignatureForError ());
124 return New.Constantify (current.Parent.Definition, current.Location).Resolve (rc);
128 public override void Emit (EmitContext ec)
130 throw new NotSupportedException ("Missing Resolve call");
134 public static readonly string UnderlyingValueField = "value__";
136 const Modifiers AllowedModifiers =
139 Modifiers.PROTECTED |
143 public Enum (NamespaceEntry ns, DeclSpace parent, TypeExpression type,
144 Modifiers mod_flags, MemberName name, Attributes attrs)
145 : base (ns, parent, name, attrs, MemberKind.Enum)
147 base_type_expr = type;
148 var accmods = IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE;
149 ModFlags = ModifiersExtensions.Check (AllowedModifiers, mod_flags, accmods, Location, Report);
150 spec = new EnumSpec (null, this, null, null, ModFlags);
155 public override AttributeTargets AttributeTargets {
157 return AttributeTargets.Enum;
161 public TypeExpr BaseTypeExpression {
163 return base_type_expr;
167 protected override TypeAttributes TypeAttr {
169 return ModifiersExtensions.TypeAttr (ModFlags, IsTopLevel) |
170 TypeAttributes.Class | TypeAttributes.Sealed | base.TypeAttr;
174 public TypeSpec UnderlyingType {
176 return ((EnumSpec) spec).UnderlyingType;
182 public void AddEnumMember (EnumMember em)
184 if (em.Name == UnderlyingValueField) {
185 Report.Error (76, em.Location, "An item in an enumeration cannot have an identifier `{0}'",
186 UnderlyingValueField);
193 public static void Error_1008 (Location loc, Report Report)
195 Report.Error (1008, loc,
196 "Type byte, sbyte, short, ushort, int, uint, long or ulong expected");
199 protected override bool DefineNestedTypes ()
201 ((EnumSpec) spec).UnderlyingType = base_type_expr == null ? TypeManager.int32_type : base_type_expr.Type;
203 TypeBuilder.DefineField (UnderlyingValueField, UnderlyingType.GetMetaInfo (),
204 FieldAttributes.Public | FieldAttributes.SpecialName | FieldAttributes.RTSpecialName);
206 if (!RootContext.StdLib)
207 RootContext.hack_corlib_enums.Add (this);
212 protected override bool DoDefineMembers ()
214 if (constants != null) {
215 for (int i = 0; i < constants.Count; ++i) {
216 EnumMember em = (EnumMember) constants [i];
217 if (em.Initializer == null) {
218 em.Initializer = new ImplicitInitializer (em, i == 0 ? null : (EnumMember) constants[i - 1]);
228 public override bool IsUnmanagedType ()
233 protected override TypeExpr[] ResolveBaseTypes (out TypeExpr base_class)
235 base_type = TypeManager.enum_type;
236 base_class = base_type_expr;
240 protected override bool VerifyClsCompliance ()
242 if (!base.VerifyClsCompliance ())
245 if (UnderlyingType == TypeManager.uint32_type ||
246 UnderlyingType == TypeManager.uint64_type ||
247 UnderlyingType == TypeManager.ushort_type) {
248 Report.Warning (3009, 1, Location, "`{0}': base type `{1}' is not CLS-compliant", GetSignatureForError (), TypeManager.CSharpName (UnderlyingType));
255 class EnumSpec : TypeSpec
259 public EnumSpec (TypeSpec declaringType, ITypeDefinition definition, TypeSpec underlyingType, Type info, Modifiers modifiers)
260 : base (MemberKind.Enum, declaringType, definition, info, modifiers | Modifiers.SEALED)
262 this.underlying = underlyingType;
265 public TypeSpec UnderlyingType {
270 if (underlying != null)
271 throw new InternalErrorException ("UnderlyingType reset");
277 public static TypeSpec GetUnderlyingType (TypeSpec t)
279 return ((EnumSpec) t.GetDefinition ()).UnderlyingType;