2010-04-06 Jb Evain <jbevain@novell.com>
[mcs.git] / mcs / enum.cs
blob1aa4e361f90f92f01f80494d38b54444d709f715
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 public readonly Enum Enum;
28 public EnumTypeExpr (Enum e)
30 this.Enum = e;
33 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
35 type = Enum.CurrentType != null ? Enum.CurrentType : Enum.TypeBuilder;
36 return this;
39 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
41 return DoResolveAsTypeStep (ec);
45 public EnumMember (Enum parent, EnumMember prev_member, string name, Expression expr,
46 Attributes attrs, Location loc)
47 : base (parent, new EnumTypeExpr (parent), name, null, Modifiers.PUBLIC,
48 attrs, loc)
50 initializer = new EnumInitializer (this, expr, prev_member);
53 static bool IsValidEnumType (Type t)
55 return (t == TypeManager.int32_type || t == TypeManager.uint32_type || t == TypeManager.int64_type ||
56 t == TypeManager.byte_type || t == TypeManager.sbyte_type || t == TypeManager.short_type ||
57 t == TypeManager.ushort_type || t == TypeManager.uint64_type || t == TypeManager.char_type ||
58 TypeManager.IsEnumType (t));
61 public override Constant ConvertInitializer (ResolveContext rc, Constant expr)
63 if (expr is EnumConstant)
64 expr = ((EnumConstant) expr).Child;
66 var underlying = ((Enum) Parent).UnderlyingType;
67 if (expr != null) {
68 expr = expr.ImplicitConversionRequired (rc, underlying, Location);
69 if (expr != null && !IsValidEnumType (expr.Type)) {
70 Enum.Error_1008 (Location, Report);
71 expr = null;
75 if (expr == null)
76 expr = New.Constantify (underlying);
78 return new EnumConstant (expr, MemberType).Resolve (rc);
81 public override bool Define ()
83 if (!ResolveMemberType ())
84 return false;
86 const FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal;
87 FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType, attr);
88 spec = new ConstSpec (this, FieldBuilder, ModFlags, initializer);
90 Parent.MemberCache.AddMember (FieldBuilder, spec);
91 TypeManager.RegisterConstant (FieldBuilder, (ConstSpec) spec);
93 return true;
97 class EnumInitializer : ConstInitializer
99 EnumMember prev;
101 public EnumInitializer (Const field, Expression init, EnumMember prev)
102 : base (field, init)
104 this.prev = prev;
107 protected override Expression DoResolveInitializer (ResolveContext rc)
109 if (expr != null)
110 return base.DoResolveInitializer (rc);
112 if (prev == null)
113 return field.ConvertInitializer (rc, null);
115 try {
116 var ec = prev.Initializer.Resolve (rc) as EnumConstant;
117 expr = ec.Increment ().Resolve (rc);
118 } catch (OverflowException) {
119 rc.Report.Error (543, field.Location,
120 "The enumerator value `{0}' is outside the range of enumerator underlying type `{1}'",
121 field.GetSignatureForError (),
122 TypeManager.CSharpName (((Enum) field.Parent).UnderlyingType));
124 expr = field.ConvertInitializer (rc, null);
127 return expr;
131 /// <summary>
132 /// Enumeration container
133 /// </summary>
134 public class Enum : TypeContainer
136 public static readonly string UnderlyingValueField = "value__";
138 TypeExpr base_type;
140 const Modifiers AllowedModifiers =
141 Modifiers.NEW |
142 Modifiers.PUBLIC |
143 Modifiers.PROTECTED |
144 Modifiers.INTERNAL |
145 Modifiers.PRIVATE;
147 public Enum (NamespaceEntry ns, DeclSpace parent, TypeExpr type,
148 Modifiers mod_flags, MemberName name, Attributes attrs)
149 : base (ns, parent, name, attrs, MemberKind.Enum)
151 this.base_type = type;
152 var accmods = IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE;
153 ModFlags = ModifiersExtensions.Check (AllowedModifiers, mod_flags, accmods, Location, Report);
156 public void AddEnumMember (EnumMember em)
158 if (em.Name == UnderlyingValueField) {
159 Report.Error (76, em.Location, "An item in an enumeration cannot have an identifier `{0}'",
160 UnderlyingValueField);
161 return;
164 AddConstant (em);
167 public static void Error_1008 (Location loc, Report Report)
169 Report.Error (1008, loc, "Type byte, sbyte, short, ushort, " +
170 "int, uint, long or ulong expected");
173 protected override bool DefineNestedTypes ()
175 if (!base.DefineNestedTypes ())
176 return false;
179 // Call MapToInternalType for corlib
181 TypeBuilder.DefineField (UnderlyingValueField, UnderlyingType,
182 FieldAttributes.Public | FieldAttributes.SpecialName
183 | FieldAttributes.RTSpecialName);
185 return true;
188 protected override bool DoDefineMembers ()
190 member_cache = new MemberCache (TypeManager.enum_type, this);
191 DefineContainerMembers (constants);
192 return true;
195 public override bool IsUnmanagedType ()
197 return true;
200 public Type UnderlyingType {
201 get {
202 return base_type.Type;
206 protected override bool VerifyClsCompliance ()
208 if (!base.VerifyClsCompliance ())
209 return false;
211 if (UnderlyingType == TypeManager.uint32_type ||
212 UnderlyingType == TypeManager.uint64_type ||
213 UnderlyingType == TypeManager.ushort_type) {
214 Report.Warning (3009, 1, Location, "`{0}': base type `{1}' is not CLS-compliant", GetSignatureForError (), TypeManager.CSharpName (UnderlyingType));
217 return true;
220 public override AttributeTargets AttributeTargets {
221 get {
222 return AttributeTargets.Enum;
226 protected override TypeAttributes TypeAttr {
227 get {
228 return ModifiersExtensions.TypeAttr (ModFlags, IsTopLevel) |
229 TypeAttributes.Class | TypeAttributes.Sealed | base.TypeAttr;
234 public class EnumSpec : TypeSpec
236 public EnumSpec (MemberKind kind, ITypeDefinition definition, TypeSpec underlyingType, Type info, string name, Modifiers modifiers)
237 : base (kind, definition, info, name, modifiers)
239 this.UnderlyingType = underlyingType;
242 public TypeSpec UnderlyingType { get; private set; }