**** Merged r36189 from MCS ****
[mono.git] / mcs / gmcs / enum.cs
1 //
2 // enum.cs: Enum handling.
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //         Ravi Pratap     (ravi@ximian.com)
6 //
7 // Licensed under the terms of the GNU GPL
8 //
9 // (C) 2001 Ximian, Inc (http://www.ximian.com)
10 //
11
12 using System;
13 using System.Collections;
14 using System.Reflection;
15 using System.Reflection.Emit;
16 using System.Globalization;
17
18 namespace Mono.CSharp {
19
20         class EnumMember: MemberCore {
21                 static string[] attribute_targets = new string [] { "field" };
22
23                 Enum parent_enum;
24                 public FieldBuilder builder;
25                 internal readonly Expression Type;
26
27                 public EnumMember (Enum parent_enum, Expression expr, string name,
28                                    Location loc, Attributes attrs):
29                         base (null, new MemberName (name), attrs, loc)
30                 {
31                         this.parent_enum = parent_enum;
32                         this.ModFlags = parent_enum.ModFlags;
33                         this.Type = expr;
34                 }
35
36                 public override void ApplyAttributeBuilder(Attribute a, CustomAttributeBuilder cb)
37                 {
38                         if (a.Type == TypeManager.marshal_as_attr_type) {
39                                 UnmanagedMarshal marshal = a.GetMarshal (this);
40                                 if (marshal != null) {
41                                         builder.SetMarshal (marshal);
42                                 }
43                                         return;
44                                 }
45
46                         if (a.Type.IsSubclassOf (TypeManager.security_attr_type)) {
47                                 a.Error_InvalidSecurityParent ();
48                                 return;
49                         }
50
51                         builder.SetCustomAttribute (cb);
52                 }
53
54                 public override AttributeTargets AttributeTargets {
55                         get {
56                                 return AttributeTargets.Field;
57                         }
58                 }
59
60                 public void DefineMember (TypeBuilder tb)
61                 {
62                         FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static
63                                 | FieldAttributes.Literal;
64                         
65                         builder = tb.DefineField (Name, tb, attr);
66                 }
67
68                 public override bool Define ()
69                 {
70                         throw new NotImplementedException ();
71                 }
72
73                 public void Emit (EmitContext ec)
74                 {
75                         if (OptAttributes != null)
76                                 OptAttributes.Emit (ec, this); 
77
78                         Emit ();
79                 }
80
81                 public override string GetSignatureForError()
82                 {
83                         return String.Concat (parent_enum.GetSignatureForError (), '.', base.GetSignatureForError ());
84                 }
85
86                 public override string[] ValidAttributeTargets {
87                         get {
88                                 return attribute_targets;
89                         }
90                 }
91
92                 protected override bool VerifyClsCompliance(DeclSpace ds)
93                 {
94                         // Because parent is TypeContainer and we have only DeclSpace parent.
95                         // Parameter replacing is required
96                         return base.VerifyClsCompliance (parent_enum);
97                 }
98
99                 // There is no base type
100                 protected override void VerifyObsoleteAttribute()
101                 {
102                 }
103         }
104
105         /// <summary>
106         ///   Enumeration container
107         /// </summary>
108         public class Enum : DeclSpace {
109                 ArrayList ordered_enums;
110                 
111                 public Expression BaseType;
112                 
113                 public Type UnderlyingType;
114
115                 Hashtable member_to_location;
116
117                 //
118                 // This is for members that have been defined
119                 //
120                 Hashtable member_to_value;
121
122                 //
123                 // This is used to mark members we're currently defining
124                 //
125                 Hashtable in_transit;
126                 
127                 ArrayList field_builders;
128                 
129                 public const int AllowedModifiers =
130                         Modifiers.NEW |
131                         Modifiers.PUBLIC |
132                         Modifiers.PROTECTED |
133                         Modifiers.INTERNAL |
134                         Modifiers.PRIVATE;
135
136                 public Enum (NamespaceEntry ns, TypeContainer parent, Expression type,
137                              int mod_flags, MemberName name, Attributes attrs, Location l)
138                         : base (ns, parent, name, attrs, l)
139                 {
140                         this.BaseType = type;
141                         ModFlags = Modifiers.Check (AllowedModifiers, mod_flags,
142                                                     IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE, l);
143
144                         ordered_enums = new ArrayList ();
145                         member_to_location = new Hashtable ();
146                         member_to_value = new Hashtable ();
147                         in_transit = new Hashtable ();
148                         field_builders = new ArrayList ();
149                 }
150
151                 /// <summary>
152                 ///   Adds @name to the enumeration space, with @expr
153                 ///   being its definition.  
154                 /// </summary>
155                 public void AddEnumMember (string name, Expression expr, Location loc, Attributes opt_attrs)
156                 {
157                         if (name == "value__") {
158                                 Report.Error (76, loc, "An item in an enumeration can't have an identifier `value__'");
159                                 return;
160                         }
161
162                         EnumMember em = new EnumMember (this, expr, name, loc, opt_attrs);
163                         if (!AddToContainer (em, false, name, ""))
164                                 return;
165
166
167                         // TODO: can be almost deleted
168                         ordered_enums.Add (name);
169                         member_to_location.Add (name, loc);
170                 }
171
172                 //
173                 // This is used by corlib compilation: we map from our
174                 // type to a type that is consumable by the DefineField
175                 //
176                 Type MapToInternalType (Type t)
177                 {
178                         if (t == TypeManager.int32_type)
179                                 return typeof (int);
180                         if (t == TypeManager.int64_type)
181                                 return typeof (long);
182                         if (t == TypeManager.uint32_type)
183                                 return typeof (uint);
184                         if (t == TypeManager.uint64_type)
185                                 return typeof (ulong);
186                         if (t == TypeManager.float_type)
187                                 return typeof (float);
188                         if (t == TypeManager.double_type)
189                                 return typeof (double);
190                         if (t == TypeManager.byte_type)
191                                 return typeof (byte);
192                         if (t == TypeManager.sbyte_type)
193                                 return typeof (sbyte);
194                         if (t == TypeManager.char_type)
195                                 return typeof (char);
196                         if (t == TypeManager.short_type)
197                                 return typeof (short);
198                         if (t == TypeManager.ushort_type)
199                                 return typeof (ushort);
200
201                         throw new Exception ();
202                 }
203                 
204                 public override TypeBuilder DefineType ()
205                 {
206                         if (TypeBuilder != null)
207                                 return TypeBuilder;
208
209                         TypeAttributes attr = Modifiers.TypeAttr (ModFlags, IsTopLevel);
210
211                         ec = new EmitContext (this, this, Location, null, null, ModFlags, false);
212
213                         attr |= TypeAttributes.Class | TypeAttributes.Sealed;
214
215                         if (!(BaseType is TypeLookupExpression)) {
216                                 Report.Error (1008, Location,
217                                               "Type byte, sbyte, short, ushort, int, uint, " +
218                                               "long, or ulong expected (got: `{0}')", BaseType);
219                                 return null;
220                         }
221
222                         TypeExpr texpr = ResolveTypeExpr (BaseType, Location);
223                         if (texpr == null)
224                                 return null;
225
226                         UnderlyingType = texpr.Type;
227
228                         if (UnderlyingType != TypeManager.int32_type &&
229                             UnderlyingType != TypeManager.uint32_type &&
230                             UnderlyingType != TypeManager.int64_type &&
231                             UnderlyingType != TypeManager.uint64_type &&
232                             UnderlyingType != TypeManager.short_type &&
233                             UnderlyingType != TypeManager.ushort_type &&
234                             UnderlyingType != TypeManager.byte_type  &&
235                             UnderlyingType != TypeManager.sbyte_type) {
236                                 Report.Error (1008, Location,
237                                               "Type byte, sbyte, short, ushort, int, uint, " +
238                                               "long, or ulong expected (got: " +
239                                               TypeManager.CSharpName (UnderlyingType) + ")");
240                                 return null;
241                         }
242
243                         if (IsTopLevel) {
244                                 if (TypeManager.NamespaceClash (Name, Location))
245                                         return null;
246                                 
247                                 ModuleBuilder builder = CodeGen.Module.Builder;
248
249                                 TypeBuilder = builder.DefineType (Name, attr, TypeManager.enum_type);
250                         } else {
251                                 TypeBuilder builder = Parent.TypeBuilder;
252
253                                 TypeBuilder = builder.DefineNestedType (
254                                         Basename, attr, TypeManager.enum_type);
255                         }
256
257                         //
258                         // Call MapToInternalType for corlib
259                         //
260                         TypeBuilder.DefineField ("value__", UnderlyingType,
261                                                  FieldAttributes.Public | FieldAttributes.SpecialName
262                                                  | FieldAttributes.RTSpecialName);
263
264                         TypeManager.AddEnumType (Name, TypeBuilder, this);
265
266                         return TypeBuilder;
267                 }
268
269                 bool IsValidEnumConstant (Expression e)
270                 {
271                         if (!(e is Constant))
272                                 return false;
273
274                         if (e is IntConstant || e is UIntConstant || e is LongConstant ||
275                             e is ByteConstant || e is SByteConstant || e is ShortConstant ||
276                             e is UShortConstant || e is ULongConstant || e is EnumConstant ||
277                             e is CharConstant)
278                                 return true;
279                         else
280                                 return false;
281                 }
282
283                 object GetNextDefaultValue (object default_value)
284                 {
285                         if (UnderlyingType == TypeManager.int32_type) {
286                                 int i = (int) default_value;
287                                 
288                                 if (i < System.Int32.MaxValue)
289                                         return ++i;
290                                 else
291                                         return null;
292                         } else if (UnderlyingType == TypeManager.uint32_type) {
293                                 uint i = (uint) default_value;
294
295                                 if (i < System.UInt32.MaxValue)
296                                         return ++i;
297                                 else
298                                         return null;
299                         } else if (UnderlyingType == TypeManager.int64_type) {
300                                 long i = (long) default_value;
301
302                                 if (i < System.Int64.MaxValue)
303                                         return ++i;
304                                 else
305                                         return null;
306                         } else if (UnderlyingType == TypeManager.uint64_type) {
307                                 ulong i = (ulong) default_value;
308
309                                 if (i < System.UInt64.MaxValue)
310                                         return ++i;
311                                 else
312                                         return null;
313                         } else if (UnderlyingType == TypeManager.short_type) {
314                                 short i = (short) default_value;
315
316                                 if (i < System.Int16.MaxValue)
317                                         return ++i;
318                                 else
319                                         return null;
320                         } else if (UnderlyingType == TypeManager.ushort_type) {
321                                 ushort i = (ushort) default_value;
322
323                                 if (i < System.UInt16.MaxValue)
324                                         return ++i;
325                                 else
326                                         return null;
327                         } else if (UnderlyingType == TypeManager.byte_type) {
328                                 byte i = (byte) default_value;
329
330                                 if (i < System.Byte.MaxValue)
331                                         return ++i;
332                                 else
333                                         return null;
334                         } else if (UnderlyingType == TypeManager.sbyte_type) {
335                                 sbyte i = (sbyte) default_value;
336
337                                 if (i < System.SByte.MaxValue)
338                                         return ++i;
339                                 else
340                                         return null;
341                         }
342
343                         return null;
344                 }
345
346                 void Error_ConstantValueCannotBeConverted (object val, Location loc)
347                 {
348                         if (val is Constant)
349                                 Report.Error (31, loc, "Constant value '" + ((Constant) val).AsString () +
350                                               "' cannot be converted" +
351                                               " to a " + TypeManager.CSharpName (UnderlyingType));
352                         else 
353                                 Report.Error (31, loc, "Constant value '" + val +
354                                               "' cannot be converted" +
355                                               " to a " + TypeManager.CSharpName (UnderlyingType));
356                         return;
357                 }
358
359                 /// <summary>
360                 ///  Determines if a standard implicit conversion exists from
361                 ///  expr_type to target_type
362                 /// </summary>
363                 public static bool ImplicitConversionExists (Type expr_type, Type target_type)
364                 {
365                         expr_type = TypeManager.TypeToCoreType (expr_type);
366
367                         if (expr_type == TypeManager.void_type)
368                                 return false;
369                         
370                         if (expr_type == target_type)
371                                 return true;
372
373                         // First numeric conversions 
374
375                         if (expr_type == TypeManager.sbyte_type){
376                                 //
377                                 // From sbyte to short, int, long, float, double.
378                                 //
379                                 if ((target_type == TypeManager.int32_type) || 
380                                     (target_type == TypeManager.int64_type) ||
381                                     (target_type == TypeManager.double_type) ||
382                                     (target_type == TypeManager.float_type)  ||
383                                     (target_type == TypeManager.short_type) ||
384                                     (target_type == TypeManager.decimal_type))
385                                         return true;
386                                 
387                         } else if (expr_type == TypeManager.byte_type){
388                                 //
389                                 // From byte to short, ushort, int, uint, long, ulong, float, double
390                                 // 
391                                 if ((target_type == TypeManager.short_type) ||
392                                     (target_type == TypeManager.ushort_type) ||
393                                     (target_type == TypeManager.int32_type) ||
394                                     (target_type == TypeManager.uint32_type) ||
395                                     (target_type == TypeManager.uint64_type) ||
396                                     (target_type == TypeManager.int64_type) ||
397                                     (target_type == TypeManager.float_type) ||
398                                     (target_type == TypeManager.double_type) ||
399                                     (target_type == TypeManager.decimal_type))
400                                         return true;
401         
402                         } else if (expr_type == TypeManager.short_type){
403                                 //
404                                 // From short to int, long, float, double
405                                 // 
406                                 if ((target_type == TypeManager.int32_type) ||
407                                     (target_type == TypeManager.int64_type) ||
408                                     (target_type == TypeManager.double_type) ||
409                                     (target_type == TypeManager.float_type) ||
410                                     (target_type == TypeManager.decimal_type))
411                                         return true;
412                                         
413                         } else if (expr_type == TypeManager.ushort_type){
414                                 //
415                                 // From ushort to int, uint, long, ulong, float, double
416                                 //
417                                 if ((target_type == TypeManager.uint32_type) ||
418                                     (target_type == TypeManager.uint64_type) ||
419                                     (target_type == TypeManager.int32_type) ||
420                                     (target_type == TypeManager.int64_type) ||
421                                     (target_type == TypeManager.double_type) ||
422                                     (target_type == TypeManager.float_type) ||
423                                     (target_type == TypeManager.decimal_type))
424                                         return true;
425                                     
426                         } else if (expr_type == TypeManager.int32_type){
427                                 //
428                                 // From int to long, float, double
429                                 //
430                                 if ((target_type == TypeManager.int64_type) ||
431                                     (target_type == TypeManager.double_type) ||
432                                     (target_type == TypeManager.float_type) ||
433                                     (target_type == TypeManager.decimal_type))
434                                         return true;
435                                         
436                         } else if (expr_type == TypeManager.uint32_type){
437                                 //
438                                 // From uint to long, ulong, float, double
439                                 //
440                                 if ((target_type == TypeManager.int64_type) ||
441                                     (target_type == TypeManager.uint64_type) ||
442                                     (target_type == TypeManager.double_type) ||
443                                     (target_type == TypeManager.float_type) ||
444                                     (target_type == TypeManager.decimal_type))
445                                         return true;
446                                         
447                         } else if ((expr_type == TypeManager.uint64_type) ||
448                                    (expr_type == TypeManager.int64_type)) {
449                                 //
450                                 // From long/ulong to float, double
451                                 //
452                                 if ((target_type == TypeManager.double_type) ||
453                                     (target_type == TypeManager.float_type) ||
454                                     (target_type == TypeManager.decimal_type))
455                                         return true;
456                                     
457                         } else if (expr_type == TypeManager.char_type){
458                                 //
459                                 // From char to ushort, int, uint, long, ulong, float, double
460                                 // 
461                                 if ((target_type == TypeManager.ushort_type) ||
462                                     (target_type == TypeManager.int32_type) ||
463                                     (target_type == TypeManager.uint32_type) ||
464                                     (target_type == TypeManager.uint64_type) ||
465                                     (target_type == TypeManager.int64_type) ||
466                                     (target_type == TypeManager.float_type) ||
467                                     (target_type == TypeManager.double_type) ||
468                                     (target_type == TypeManager.decimal_type))
469                                         return true;
470
471                         } else if (expr_type == TypeManager.float_type){
472                                 //
473                                 // float to double
474                                 //
475                                 if (target_type == TypeManager.double_type)
476                                         return true;
477                         }       
478                         
479                         return false;
480                 }
481
482                 //
483                 // Horrible, horrible.  But there is no other way we can pass the EmitContext
484                 // to the recursive definition triggered by the evaluation of a forward
485                 // expression
486                 //
487                 static EmitContext current_ec = null;
488                 
489                 /// <summary>
490                 ///  This is used to lookup the value of an enum member. If the member is undefined,
491                 ///  it attempts to define it and return its value
492                 /// </summary>
493                 public object LookupEnumValue (EmitContext ec, string name, Location loc)
494                 {
495                         
496                         object default_value = null;
497                         Constant c = null;
498
499                         default_value = member_to_value [name];
500
501                         if (default_value != null)
502                                 return default_value;
503
504                         //
505                         // This may happen if we're calling a method in System.Enum, for instance
506                         // Enum.IsDefined().
507                         //
508                         if (!defined_names.Contains (name))
509                                 return null;
510
511                         if (in_transit.Contains (name)) {
512                                 Report.Error (110, loc, "The evaluation of the constant value for `" +
513                                               Name + "." + name + "' involves a circular definition.");
514                                 return null;
515                         }
516
517                         //
518                         // So if the above doesn't happen, we have a member that is undefined
519                         // We now proceed to define it 
520                         //
521                         Expression val = this [name];
522
523                         if (val == null) {
524                                 
525                                 int idx = ordered_enums.IndexOf (name);
526
527                                 if (idx == 0)
528                                         default_value = 0;
529                                 else {
530                                         for (int i = 0; i < idx; ++i) {
531                                                 string n = (string) ordered_enums [i];
532                                                 Location m_loc = (Mono.CSharp.Location)
533                                                         member_to_location [n];
534                                                 in_transit.Add (name, true);
535
536                                                 EmitContext old_ec = current_ec;
537                                                 current_ec = ec;
538                         
539                                                 default_value = LookupEnumValue (ec, n, m_loc);
540
541                                                 current_ec = old_ec;
542                                                 
543                                                 in_transit.Remove (name);
544                                                 if (default_value == null)
545                                                         return null;
546                                         }
547                                         
548                                         default_value = GetNextDefaultValue (default_value);
549                                 }
550                                 
551                         } else {
552                                 bool old = ec.InEnumContext;
553                                 ec.InEnumContext = true;
554                                 in_transit.Add (name, true);
555
556                                 EmitContext old_ec = current_ec;
557                                 current_ec = ec;
558                                 val = val.Resolve (ec);
559                                 current_ec = old_ec;
560                                 
561                                 in_transit.Remove (name);
562                                 ec.InEnumContext = old;
563
564                                 if (val == null)
565                                         return null;
566
567                                 if (!IsValidEnumConstant (val)) {
568                                         Report.Error (
569                                                 1008, loc,
570                                                 "Type byte, sbyte, short, ushort, int, uint, long, or " +
571                                                 "ulong expected (have: " + val + ")");
572                                         return null;
573                                 }
574
575                                 c = (Constant) val;
576                                 default_value = c.GetValue ();
577
578                                 if (default_value == null) {
579                                         Error_ConstantValueCannotBeConverted (c, loc);
580                                         return null;
581                                 }
582
583                                 if (val is EnumConstant){
584                                         Type etype = TypeManager.EnumToUnderlying (c.Type);
585                                         
586                                         if (!ImplicitConversionExists (etype, UnderlyingType)){
587                                                 Convert.Error_CannotImplicitConversion (
588                                                         loc, c.Type, UnderlyingType);
589                                                 return null;
590                                         }
591                                 }
592                         }
593
594                         EnumMember em = (EnumMember) defined_names [name];
595                         em.DefineMember (TypeBuilder);
596
597                         bool fail;
598                         default_value = TypeManager.ChangeType (default_value, UnderlyingType, out fail);
599                         if (fail){
600                                 Error_ConstantValueCannotBeConverted (c, loc);
601                                 return null;
602                         }
603
604                         em.builder.SetConstant (default_value);
605                         field_builders.Add (em.builder);
606                         member_to_value [name] = default_value;
607
608                         if (!TypeManager.RegisterFieldValue (em.builder, default_value))
609                                 return null;
610
611                         return default_value;
612                 }
613
614                 public override bool DefineMembers (TypeContainer parent)
615                 {
616                         return true;
617                 }
618                 
619                 public override bool Define ()
620                 {
621                         //
622                         // If there was an error during DefineEnum, return
623                         //
624                         if (TypeBuilder == null)
625                                 return false;
626
627                         ec = new EmitContext (this, this, Location, null, UnderlyingType, ModFlags, false);
628                         
629                         object default_value = 0;
630                         
631                 
632                         foreach (string name in ordered_enums) {
633                                 //
634                                 // Have we already been defined, thanks to some cross-referencing ?
635                                 // 
636                                 if (member_to_value.Contains (name))
637                                         continue;
638                                 
639                                 Location loc = (Mono.CSharp.Location) member_to_location [name];
640
641                                 if (this [name] != null) {
642                                         default_value = LookupEnumValue (ec, name, loc);
643
644                                         if (default_value == null)
645                                                 return true;
646                                 } else {
647                                         if (name == "value__"){
648                                                 Report.Error (76, loc, "The name `value__' is reserved for enumerations");
649                                                 return false;
650                                         }
651
652                                         EnumMember em = (EnumMember) defined_names [name];
653
654                                         em.DefineMember (TypeBuilder);
655                                         FieldBuilder fb = em.builder;
656                                         
657                                         if (default_value == null) {
658                                            Report.Error (543, loc, "Enumerator value for '" + name + "' is too large to " +
659                                                               "fit in its type");
660                                                 return false;
661                                         }
662
663                                         bool fail;
664                                         default_value = TypeManager.ChangeType (default_value, UnderlyingType, out fail);
665                                         if (fail){
666                                                 Error_ConstantValueCannotBeConverted (default_value, loc);
667                                                 return false;
668                                         }
669
670                                         fb.SetConstant (default_value);
671                                         field_builders.Add (fb);
672                                         member_to_value [name] = default_value;
673                                         
674                                         if (!TypeManager.RegisterFieldValue (fb, default_value))
675                                                 return false;
676                                 }
677
678                                 default_value = GetNextDefaultValue (default_value);
679                         }
680
681                         return true;
682                 }
683
684                 public override void Emit ()
685                 {
686                         if (OptAttributes != null) {
687                                 OptAttributes.Emit (ec, this);
688                         }
689
690                         foreach (EnumMember em in defined_names.Values) {
691                                 em.Emit (ec);
692                         }
693
694                         base.Emit ();
695                 }
696                 
697                 void VerifyClsName ()
698                 {
699                         Hashtable ht = new Hashtable ();
700                         foreach (string name in ordered_enums) {
701                                 string locase = name.ToLower (System.Globalization.CultureInfo.InvariantCulture);
702                                 if (!ht.Contains (locase)) {
703                                         ht.Add (locase, defined_names [name]);
704                                         continue;
705                                 }
706  
707                                 MemberCore conflict = (MemberCore)ht [locase];
708                                 Report.SymbolRelatedToPreviousError (conflict);
709                                 conflict = GetDefinition (name);
710                                 Report.Error (3005, conflict.Location, "Identifier '{0}' differing only in case is not CLS-compliant", conflict.GetSignatureForError ());
711                         }
712                 }
713
714                 protected override bool VerifyClsCompliance (DeclSpace ds)
715                 {
716                         if (!base.VerifyClsCompliance (ds))
717                                 return false;
718
719                         VerifyClsName ();
720
721                         if (!AttributeTester.IsClsCompliant (UnderlyingType)) {
722                                 Report.Error (3009, Location, "'{0}': base type '{1}' is not CLS-compliant", GetSignatureForError (), TypeManager.CSharpName (UnderlyingType));
723                         }
724
725                         return true;
726                 }
727                 
728                 /// <summary>
729                 /// Returns full enum name.
730                 /// </summary>
731                 string GetEnumeratorName (string valueName)
732                 {
733                         return String.Concat (Name, ".", valueName);
734                 }
735
736                 //
737                 // IMemberFinder
738                 //
739                 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
740                                                         MemberFilter filter, object criteria)
741                 {
742                         ArrayList members = new ArrayList ();
743
744                         if ((mt & MemberTypes.Field) != 0) {
745                                 if (criteria is string){
746                                         if (member_to_value [criteria] == null && current_ec != null){
747                                                 LookupEnumValue (current_ec, (string) criteria, Location.Null);
748                                         }
749                                 }
750                                 
751                                 foreach (FieldBuilder fb in field_builders)
752                                         if (filter (fb, criteria) == true)
753                                                 members.Add (fb);
754                         }
755
756                         return new MemberList (members);
757                 }
758
759                 public override MemberCache MemberCache {
760                         get {
761                                 return null;
762                         }
763                 }
764
765                 public ArrayList ValueNames {
766                         get {
767                                 return ordered_enums;
768                         }
769                 }
770
771                 // indexer
772                 public Expression this [string name] {
773                         get {
774                                 return ((EnumMember) defined_names [name]).Type;
775                         }
776                 }
777
778                 public override AttributeTargets AttributeTargets {
779                         get {
780                                 return AttributeTargets.Enum;
781                         }
782                 }
783
784                 protected override void VerifyObsoleteAttribute()
785                 {
786                         // UnderlyingType is never obsolete
787                 }
788         }
789 }