Fix bug #566087.
[mcs.git] / mcs / enum.cs
blobafea3f6913f7427cca204c2a03b12de1fa09e3fe
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 {
23 protected readonly Enum ParentEnum;
24 protected readonly Expression ValueExpr;
25 readonly EnumMember prev_member;
27 public EnumMember (Enum parent, EnumMember prev_member, string name, Expression expr,
28 Attributes attrs, Location loc)
29 : base (parent, new EnumTypeExpr (parent), name, expr, Modifiers.PUBLIC,
30 attrs, loc)
32 this.ParentEnum = parent;
33 this.ValueExpr = expr;
34 this.prev_member = prev_member;
37 protected class EnumTypeExpr : TypeExpr
39 public readonly Enum Enum;
41 public EnumTypeExpr (Enum e)
43 this.Enum = e;
46 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
48 type = Enum.CurrentType != null ? Enum.CurrentType : Enum.TypeBuilder;
49 return this;
52 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
54 return DoResolveAsTypeStep (ec);
58 static bool IsValidEnumType (Type t)
60 return (t == TypeManager.int32_type || t == TypeManager.uint32_type || t == TypeManager.int64_type ||
61 t == TypeManager.byte_type || t == TypeManager.sbyte_type || t == TypeManager.short_type ||
62 t == TypeManager.ushort_type || t == TypeManager.uint64_type || t == TypeManager.char_type ||
63 TypeManager.IsEnumType (t));
66 public object Value {
67 get { return ResolveValue () ? value.GetValue () : null; }
70 public override bool Define ()
72 if (!ResolveMemberType ())
73 return false;
75 const FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal;
76 FieldBuilder = Parent.TypeBuilder.DefineField (Name, MemberType, attr);
77 Parent.MemberCache.AddMember (FieldBuilder, this);
78 TypeManager.RegisterConstant (FieldBuilder, this);
79 return true;
82 protected override Constant DoResolveValue (ResolveContext ec)
84 if (ValueExpr != null) {
85 Constant c = ValueExpr.ResolveAsConstant (ec, this);
86 if (c == null)
87 return null;
89 if (c is EnumConstant)
90 c = ((EnumConstant)c).Child;
92 c = c.ImplicitConversionRequired (ec, ParentEnum.UnderlyingType, Location);
93 if (c == null)
94 return null;
96 if (!IsValidEnumType (c.Type)) {
97 Enum.Error_1008 (Location, ec.Report);
98 return null;
101 return new EnumConstant (c, MemberType).Resolve (ec);
104 if (prev_member == null)
105 return new EnumConstant (New.Constantify (ParentEnum.UnderlyingType), MemberType).Resolve (ec);
107 if (!prev_member.ResolveValue ())
108 return null;
110 try {
111 return ((EnumConstant) prev_member.value).Increment ();
112 } catch (OverflowException) {
113 Report.Error (543, Location, "The enumerator value `{0}' is too " +
114 "large to fit in its type `{1}'", GetSignatureForError (),
115 TypeManager.CSharpName (ParentEnum.UnderlyingType));
116 return null;
121 /// <summary>
122 /// Enumeration container
123 /// </summary>
124 public class Enum : TypeContainer
126 public static readonly string UnderlyingValueField = "value__";
128 TypeExpr base_type;
130 const Modifiers AllowedModifiers =
131 Modifiers.NEW |
132 Modifiers.PUBLIC |
133 Modifiers.PROTECTED |
134 Modifiers.INTERNAL |
135 Modifiers.PRIVATE;
137 public Enum (NamespaceEntry ns, DeclSpace parent, TypeExpr type,
138 Modifiers mod_flags, MemberName name, Attributes attrs)
139 : base (ns, parent, name, attrs, Kind.Enum)
141 this.base_type = type;
142 var accmods = IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE;
143 ModFlags = ModifiersExtensions.Check (AllowedModifiers, mod_flags, accmods, Location, Report);
146 public void AddEnumMember (EnumMember em)
148 if (em.Name == UnderlyingValueField) {
149 Report.Error (76, em.Location, "An item in an enumeration cannot have an identifier `{0}'",
150 UnderlyingValueField);
151 return;
154 AddConstant (em);
157 public static void Error_1008 (Location loc, Report Report)
159 Report.Error (1008, loc, "Type byte, sbyte, short, ushort, " +
160 "int, uint, long or ulong expected");
163 protected override bool DefineNestedTypes ()
165 if (!base.DefineNestedTypes ())
166 return false;
169 // Call MapToInternalType for corlib
171 TypeBuilder.DefineField (UnderlyingValueField, UnderlyingType,
172 FieldAttributes.Public | FieldAttributes.SpecialName
173 | FieldAttributes.RTSpecialName);
175 return true;
178 protected override bool DoDefineMembers ()
180 member_cache = new MemberCache (TypeManager.enum_type, this);
181 DefineContainerMembers (constants);
182 return true;
185 public override bool IsUnmanagedType ()
187 return true;
190 public Type UnderlyingType {
191 get {
192 return base_type.Type;
196 protected override bool VerifyClsCompliance ()
198 if (!base.VerifyClsCompliance ())
199 return false;
201 if (UnderlyingType == TypeManager.uint32_type ||
202 UnderlyingType == TypeManager.uint64_type ||
203 UnderlyingType == TypeManager.ushort_type) {
204 Report.Warning (3009, 1, Location, "`{0}': base type `{1}' is not CLS-compliant", GetSignatureForError (), TypeManager.CSharpName (UnderlyingType));
207 return true;
210 public override AttributeTargets AttributeTargets {
211 get {
212 return AttributeTargets.Enum;
216 protected override TypeAttributes TypeAttr {
217 get {
218 return ModifiersExtensions.TypeAttr (ModFlags, IsTopLevel) |
219 TypeAttributes.Class | TypeAttributes.Sealed | base.TypeAttr;