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)
12 // Copyright 2011 Xamarin Inc
18 using MetaType
= IKVM
.Reflection
.Type
;
19 using IKVM
.Reflection
;
21 using MetaType
= System
.Type
;
22 using System
.Reflection
;
28 public class EnumMember
: Const
31 class MemberTypeDelegator
: TypeDelegator
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
{
48 return underlyingType
;
54 class EnumTypeExpr
: TypeExpr
56 public override TypeSpec
ResolveAsType (IMemberContext ec
, bool allowUnboundTypeArguments
)
58 type
= ec
.CurrentType
;
59 eclass
= ExprClass
.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
:
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
;
95 expr
= expr
.ImplicitConversionRequired (rc
, underlying
);
96 if (expr
!= null && !IsValidEnumType (expr
.Type
)) {
97 en
.Error_UnderlyingType (Location
);
103 expr
= New
.Constantify (underlying
, Location
);
105 return new EnumConstant (expr
, MemberType
);
108 public override bool Define ()
110 if (!ResolveMemberType ())
113 MetaType ftype
= MemberType
.GetMetaInfo ();
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 ());
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
);
130 public override void Accept (StructuralVisitor visitor
)
132 visitor
.Visit (this);
138 /// Enumeration container
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
;
156 public override bool ContainsEmitWithAwait ()
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
170 return New
.Constantify (current
.Parent
.Definition
, Location
);
173 var c
= ((ConstSpec
) prev
.Spec
).GetConstant (rc
) as EnumConstant
;
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
=
196 Modifiers
.PROTECTED
|
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
);
213 public override AttributeTargets AttributeTargets
{
215 return AttributeTargets
.Enum
;
219 public FullNamedExpression BaseTypeExpression
{
221 return underlying_type_expr
;
225 protected override TypeAttributes TypeAttr
{
227 return base.TypeAttr
| TypeAttributes
.Class
| TypeAttributes
.Sealed
;
231 public TypeSpec UnderlyingType
{
233 return ((EnumSpec
) spec
).UnderlyingType
;
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
);
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 ()
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
);
275 ut
= Compiler
.BuiltinTypes
.Int
;
277 ((EnumSpec
) spec
).UnderlyingType
= ut
;
279 TypeBuilder
.DefineField (UnderlyingValueField
, UnderlyingType
.GetMetaInfo (),
280 FieldAttributes
.Public
| FieldAttributes
.SpecialName
| FieldAttributes
.RTSpecialName
);
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]);
299 public override bool IsUnmanagedType ()
304 protected override TypeSpec
[] ResolveBaseTypes (out FullNamedExpression base_class
)
306 base_type
= Compiler
.BuiltinTypes
.Enum
;
311 protected override bool VerifyClsCompliance ()
313 if (!base.VerifyClsCompliance ())
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 ());
329 class EnumSpec
: TypeSpec
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
{
344 if (underlying
!= null)
345 throw new InternalErrorException ("UnderlyingType reset");
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
: