2010-06-21 Atsushi Enomoto <atsushi@ximian.com>
[mcs.git] / mcs / enum.cs
blob2f399c5a2926f46350ac6461af6a7632c95c79cd
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)
14 using System;
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;
29 return this;
32 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
34 return DoResolveAsTypeStep (ec);
38 public EnumMember (Enum parent, EnumMember prev_member, string name, Expression expr,
39 Attributes attrs, Location loc)
40 : base (parent, new EnumTypeExpr (), name, null, Modifiers.PUBLIC,
41 attrs, loc)
43 initializer = new EnumInitializer (this, expr, prev_member);
46 static bool IsValidEnumType (TypeSpec t)
48 return (t == TypeManager.int32_type || t == TypeManager.uint32_type || t == TypeManager.int64_type ||
49 t == TypeManager.byte_type || t == TypeManager.sbyte_type || t == TypeManager.short_type ||
50 t == TypeManager.ushort_type || t == TypeManager.uint64_type || t == TypeManager.char_type ||
51 TypeManager.IsEnumType (t));
54 public override Constant ConvertInitializer (ResolveContext rc, Constant expr)
56 if (expr is EnumConstant)
57 expr = ((EnumConstant) expr).Child;
59 var underlying = ((Enum) Parent).UnderlyingType;
60 if (expr != null) {
61 expr = expr.ImplicitConversionRequired (rc, underlying, Location);
62 if (expr != null && !IsValidEnumType (expr.Type)) {
63 Enum.Error_1008 (Location, Report);
64 expr = null;
68 if (expr == null)
69 expr = New.Constantify (underlying);
71 return new EnumConstant (expr, MemberType).Resolve (rc);
74 public override bool Define ()
76 if (!ResolveMemberType ())
77 return false;
79 const FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal;
80 FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType.GetMetaInfo (), attr);
81 spec = new ConstSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags, initializer);
83 Parent.MemberCache.AddMember (spec);
84 return true;
88 class EnumInitializer : ConstInitializer
90 EnumMember prev;
92 public EnumInitializer (Const field, Expression init, EnumMember prev)
93 : base (field, init)
95 this.prev = prev;
98 protected override Expression DoResolveInitializer (ResolveContext rc)
100 if (expr != null)
101 return base.DoResolveInitializer (rc);
103 if (prev == null)
104 return field.ConvertInitializer (rc, null);
106 try {
107 var ec = prev.DefineValue () as EnumConstant;
108 expr = ec.Increment ().Resolve (rc);
109 } catch (OverflowException) {
110 rc.Report.Error (543, field.Location,
111 "The enumerator value `{0}' is outside the range of enumerator underlying type `{1}'",
112 field.GetSignatureForError (),
113 TypeManager.CSharpName (((Enum) field.Parent).UnderlyingType));
115 expr = field.ConvertInitializer (rc, null);
118 return expr;
122 /// <summary>
123 /// Enumeration container
124 /// </summary>
125 public class Enum : TypeContainer
127 public static readonly string UnderlyingValueField = "value__";
129 const Modifiers AllowedModifiers =
130 Modifiers.NEW |
131 Modifiers.PUBLIC |
132 Modifiers.PROTECTED |
133 Modifiers.INTERNAL |
134 Modifiers.PRIVATE;
136 public Enum (NamespaceEntry ns, DeclSpace parent, TypeExpression type,
137 Modifiers mod_flags, MemberName name, Attributes attrs)
138 : base (ns, parent, name, attrs, MemberKind.Enum)
140 base_type_expr = type;
141 var accmods = IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE;
142 ModFlags = ModifiersExtensions.Check (AllowedModifiers, mod_flags, accmods, Location, Report);
143 spec = new EnumSpec (null, this, null, null, ModFlags);
146 #region Properties
148 public override AttributeTargets AttributeTargets {
149 get {
150 return AttributeTargets.Enum;
154 public TypeExpr BaseTypeExpression {
155 get {
156 return base_type_expr;
160 protected override TypeAttributes TypeAttr {
161 get {
162 return ModifiersExtensions.TypeAttr (ModFlags, IsTopLevel) |
163 TypeAttributes.Class | TypeAttributes.Sealed | base.TypeAttr;
167 public TypeSpec UnderlyingType {
168 get {
169 return ((EnumSpec) spec).UnderlyingType;
173 #endregion
175 public void AddEnumMember (EnumMember em)
177 if (em.Name == UnderlyingValueField) {
178 Report.Error (76, em.Location, "An item in an enumeration cannot have an identifier `{0}'",
179 UnderlyingValueField);
180 return;
183 AddConstant (em);
186 public static void Error_1008 (Location loc, Report Report)
188 Report.Error (1008, loc,
189 "Type byte, sbyte, short, ushort, int, uint, long or ulong expected");
192 protected override bool DefineNestedTypes ()
194 ((EnumSpec) spec).UnderlyingType = base_type_expr == null ? TypeManager.int32_type : base_type_expr.Type;
196 TypeBuilder.DefineField (UnderlyingValueField, UnderlyingType.GetMetaInfo (),
197 FieldAttributes.Public | FieldAttributes.SpecialName | FieldAttributes.RTSpecialName);
199 if (!RootContext.StdLib)
200 RootContext.hack_corlib_enums.Add (this);
202 return true;
205 protected override bool DoDefineMembers ()
207 DefineContainerMembers (constants);
208 return true;
211 public override bool IsUnmanagedType ()
213 return true;
216 protected override TypeExpr[] ResolveBaseTypes (out TypeExpr base_class)
218 base_type = TypeManager.enum_type;
219 base_class = base_type_expr;
220 return null;
223 protected override bool VerifyClsCompliance ()
225 if (!base.VerifyClsCompliance ())
226 return false;
228 if (UnderlyingType == TypeManager.uint32_type ||
229 UnderlyingType == TypeManager.uint64_type ||
230 UnderlyingType == TypeManager.ushort_type) {
231 Report.Warning (3009, 1, Location, "`{0}': base type `{1}' is not CLS-compliant", GetSignatureForError (), TypeManager.CSharpName (UnderlyingType));
234 return true;
238 class EnumSpec : TypeSpec
240 TypeSpec underlying;
242 public EnumSpec (TypeSpec declaringType, ITypeDefinition definition, TypeSpec underlyingType, Type info, Modifiers modifiers)
243 : base (MemberKind.Enum, declaringType, definition, info, modifiers | Modifiers.SEALED)
245 this.underlying = underlyingType;
248 public TypeSpec UnderlyingType {
249 get {
250 return underlying;
252 set {
253 if (underlying != null)
254 throw new InternalErrorException ("UnderlyingType reset");
256 underlying = value;
260 public static TypeSpec GetUnderlyingType (TypeSpec t)
262 return ((EnumSpec) t.GetDefinition ()).UnderlyingType;