[LoongArch64] Part-5:add loongarch support in some files for LoongArch64. (#21769)
[mono-project.git] / mcs / mcs / enum.cs
blobf124338ba558812c20521b9db4c026baf61b9a0a
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)
12 // Copyright 2011 Xamarin Inc
15 using System;
17 #if STATIC
18 using MetaType = IKVM.Reflection.Type;
19 using IKVM.Reflection;
20 #else
21 using MetaType = System.Type;
22 using System.Reflection;
23 #endif
25 namespace Mono.CSharp
28 public class EnumMember : Const
30 #if !STATIC
31 class MemberTypeDelegator : TypeDelegator
33 Type underlyingType;
35 public MemberTypeDelegator (Type delegatingType, Type underlyingType)
36 : base (delegatingType)
38 this.underlyingType = underlyingType;
41 public override Type GetEnumUnderlyingType ()
43 return underlyingType;
46 public override Type UnderlyingSystemType {
47 get {
48 return underlyingType;
52 #endif
54 class EnumTypeExpr : TypeExpr
56 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
58 type = ec.CurrentType;
59 eclass = ExprClass.Type;
60 return type;
64 public EnumMember (Enum parent, MemberName name, Attributes attrs)
65 : base (parent, new EnumTypeExpr (), Modifiers.PUBLIC, name, attrs)
69 static bool IsValidEnumType (TypeSpec t)
71 switch (t.BuiltinType) {
72 case BuiltinTypeSpec.Type.Int:
73 case BuiltinTypeSpec.Type.UInt:
74 case BuiltinTypeSpec.Type.Long:
75 case BuiltinTypeSpec.Type.Byte:
76 case BuiltinTypeSpec.Type.SByte:
77 case BuiltinTypeSpec.Type.Short:
78 case BuiltinTypeSpec.Type.UShort:
79 case BuiltinTypeSpec.Type.ULong:
80 case BuiltinTypeSpec.Type.Char:
81 return true;
82 default:
83 return t.IsEnum;
87 public override Constant ConvertInitializer (ResolveContext rc, Constant expr)
89 if (expr is EnumConstant)
90 expr = ((EnumConstant) expr).Child;
92 var en = (Enum)Parent;
93 var underlying = en.UnderlyingType;
94 if (expr != null) {
95 expr = expr.ImplicitConversionRequired (rc, underlying);
96 if (expr != null && !IsValidEnumType (expr.Type)) {
97 en.Error_UnderlyingType (Location);
98 expr = null;
102 if (expr == null)
103 expr = New.Constantify (underlying, Location);
105 return new EnumConstant (expr, MemberType);
108 public override bool Define ()
110 if (!ResolveMemberType ())
111 return false;
113 MetaType ftype = MemberType.GetMetaInfo ();
114 #if !STATIC
116 // Workaround for .net SRE limitation which cannot define field of unbaked enum type
117 // which is how all enums are declared
119 ftype = new MemberTypeDelegator (ftype, ((Enum)Parent).UnderlyingType.GetMetaInfo ());
120 #endif
122 const FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal;
123 FieldBuilder = Parent.TypeBuilder.DefineField (Name, ftype, attr);
124 spec = new ConstSpec (Parent.Definition, this, MemberType, FieldBuilder, ModFlags, initializer);
126 Parent.MemberCache.AddMember (spec);
127 return true;
130 public override void Accept (StructuralVisitor visitor)
132 visitor.Visit (this);
137 /// <summary>
138 /// Enumeration container
139 /// </summary>
140 public class Enum : TypeDefinition
143 // Implicit enum member initializer, used when no constant value is provided
145 sealed class ImplicitInitializer : Expression
147 readonly EnumMember prev;
148 readonly EnumMember current;
150 public ImplicitInitializer (EnumMember current, EnumMember prev)
152 this.current = current;
153 this.prev = prev;
156 public override bool ContainsEmitWithAwait ()
158 return false;
161 public override Expression CreateExpressionTree (ResolveContext ec)
163 throw new NotSupportedException ("Missing Resolve call");
166 protected override Expression DoResolve (ResolveContext rc)
168 // We are the first member
169 if (prev == null) {
170 return New.Constantify (current.Parent.Definition, Location);
173 var c = ((ConstSpec) prev.Spec).GetConstant (rc) as EnumConstant;
174 try {
175 return c.Increment ();
176 } catch (OverflowException) {
177 rc.Report.Error (543, current.Location,
178 "The enumerator value `{0}' is outside the range of enumerator underlying type `{1}'",
179 current.GetSignatureForError (), ((Enum) current.Parent).UnderlyingType.GetSignatureForError ());
181 return New.Constantify (current.Parent.Definition, current.Location);
185 public override void Emit (EmitContext ec)
187 throw new NotSupportedException ("Missing Resolve call");
191 public static readonly string UnderlyingValueField = "value__";
193 const Modifiers AllowedModifiers =
194 Modifiers.NEW |
195 Modifiers.PUBLIC |
196 Modifiers.PROTECTED |
197 Modifiers.INTERNAL |
198 Modifiers.PRIVATE;
200 readonly FullNamedExpression underlying_type_expr;
202 public Enum (TypeContainer parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs)
203 : base (parent, name, attrs, MemberKind.Enum)
205 underlying_type_expr = type;
206 var accmods = IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE;
207 ModFlags = ModifiersExtensions.Check (AllowedModifiers, mod_flags, accmods, Location, Report);
208 spec = new EnumSpec (null, this, null, null, ModFlags);
211 #region Properties
213 public override AttributeTargets AttributeTargets {
214 get {
215 return AttributeTargets.Enum;
219 public FullNamedExpression BaseTypeExpression {
220 get {
221 return underlying_type_expr;
225 protected override TypeAttributes TypeAttr {
226 get {
227 return base.TypeAttr | TypeAttributes.Class | TypeAttributes.Sealed;
231 public TypeSpec UnderlyingType {
232 get {
233 return ((EnumSpec) spec).UnderlyingType;
237 #endregion
239 public override void Accept (StructuralVisitor visitor)
241 visitor.Visit (this);
244 public void AddEnumMember (EnumMember em)
246 if (em.Name == UnderlyingValueField) {
247 Report.Error (76, em.Location, "An item in an enumeration cannot have an identifier `{0}'",
248 UnderlyingValueField);
249 return;
252 AddMember (em);
255 public void Error_UnderlyingType (Location loc)
257 Report.Error (1008, loc,
258 "Type byte, sbyte, short, ushort, int, uint, long or ulong expected");
261 protected override void DoDefineContainer ()
263 TypeSpec ut;
264 if (underlying_type_expr != null) {
265 ut = underlying_type_expr.ResolveAsType (this);
266 if (!EnumSpec.IsValidUnderlyingType (ut)) {
267 Error_UnderlyingType (underlying_type_expr.Location);
268 ut = null;
270 } else {
271 ut = null;
274 if (ut == null)
275 ut = Compiler.BuiltinTypes.Int;
277 ((EnumSpec) spec).UnderlyingType = ut;
279 TypeBuilder.DefineField (UnderlyingValueField, UnderlyingType.GetMetaInfo (),
280 FieldAttributes.Public | FieldAttributes.SpecialName | FieldAttributes.RTSpecialName);
282 DefineBaseTypes ();
285 protected override bool DoDefineMembers ()
287 for (int i = 0; i < Members.Count; ++i) {
288 EnumMember em = (EnumMember) Members[i];
289 if (em.Initializer == null) {
290 em.Initializer = new ImplicitInitializer (em, i == 0 ? null : (EnumMember) Members[i - 1]);
293 em.Define ();
296 return true;
299 public override bool IsUnmanagedType ()
301 return true;
304 protected override TypeSpec[] ResolveBaseTypes (out FullNamedExpression base_class)
306 base_type = Compiler.BuiltinTypes.Enum;
307 base_class = null;
308 return null;
311 protected override bool VerifyClsCompliance ()
313 if (!base.VerifyClsCompliance ())
314 return false;
316 switch (UnderlyingType.BuiltinType) {
317 case BuiltinTypeSpec.Type.UInt:
318 case BuiltinTypeSpec.Type.ULong:
319 case BuiltinTypeSpec.Type.UShort:
320 Report.Warning (3009, 1, Location, "`{0}': base type `{1}' is not CLS-compliant",
321 GetSignatureForError (), UnderlyingType.GetSignatureForError ());
322 break;
325 return true;
329 class EnumSpec : TypeSpec
331 TypeSpec underlying;
333 public EnumSpec (TypeSpec declaringType, ITypeDefinition definition, TypeSpec underlyingType, MetaType info, Modifiers modifiers)
334 : base (MemberKind.Enum, declaringType, definition, info, modifiers | Modifiers.SEALED)
336 this.underlying = underlyingType;
339 public TypeSpec UnderlyingType {
340 get {
341 return underlying;
343 set {
344 if (underlying != null)
345 throw new InternalErrorException ("UnderlyingType reset");
347 underlying = value;
351 public static TypeSpec GetUnderlyingType (TypeSpec t)
353 return ((EnumSpec) t.GetDefinition ()).UnderlyingType;
356 public static bool IsValidUnderlyingType (TypeSpec type)
358 switch (type.BuiltinType) {
359 case BuiltinTypeSpec.Type.Int:
360 case BuiltinTypeSpec.Type.UInt:
361 case BuiltinTypeSpec.Type.Long:
362 case BuiltinTypeSpec.Type.Byte:
363 case BuiltinTypeSpec.Type.SByte:
364 case BuiltinTypeSpec.Type.Short:
365 case BuiltinTypeSpec.Type.UShort:
366 case BuiltinTypeSpec.Type.ULong:
367 return true;
370 return false;