**** Merged from MCS ****
[mono.git] / mcs / gmcs / decl.cs
1 //
2 // decl.cs: Declaration base class for structs, classes, enums and interfaces.
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //         Marek Safar (marek.safar@seznam.cz)
6 //
7 // Licensed under the terms of the GNU GPL
8 //
9 // (C) 2001 Ximian, Inc (http://www.ximian.com)
10 //
11 // TODO: Move the method verification stuff from the class.cs and interface.cs here
12 //
13
14 using System;
15 using System.Text;
16 using System.Collections;
17 using System.Globalization;
18 using System.Reflection.Emit;
19 using System.Reflection;
20
21 namespace Mono.CSharp {
22
23         public class MemberName {
24                 public readonly string Name;
25                 public readonly TypeArguments TypeArguments;
26
27                 public readonly MemberName Left;
28
29                 public static readonly MemberName Null = new MemberName ("");
30
31                 public MemberName (string name)
32                 {
33                         this.Name = name;
34                 }
35
36                 public MemberName (string name, TypeArguments args)
37                         : this (name)
38                 {
39                         this.TypeArguments = args;
40                 }
41
42                 public MemberName (MemberName left, string name, TypeArguments args)
43                         : this (name, args)
44                 {
45                         this.Left = left;
46                 }
47
48                 public MemberName (MemberName left, MemberName right)
49                         : this (left, right.Name, right.TypeArguments)
50                 {
51                 }
52
53                 public string GetName ()
54                 {
55                         if (Left != null)
56                                 return Left.GetName () + "." + Name;
57                         else
58                                 return Name;
59                 }
60
61                 public bool IsGeneric {
62                         get {
63                                 if (TypeArguments != null)
64                                         return true;
65                                 else if (Left != null)
66                                         return Left.IsGeneric;
67                                 else
68                                         return false;
69                         }
70                 }
71
72                 public string GetName (bool is_generic)
73                 {
74                         string name = is_generic ? Basename : Name;
75                         if (Left != null)
76                                 return Left.GetName (is_generic) + "." + name;
77                         else
78                                 return name;
79                 }
80
81                 public int CountTypeArguments {
82                         get {
83                                 if (TypeArguments == null)
84                                         return 0;
85                                 else
86                                         return TypeArguments.Count;
87                         }
88                 }
89
90                 public string GetMethodName ()
91                 {
92                         if (Left != null)
93                                 return Left.GetFullName () + "." + Name;
94                         else
95                                 return Name;
96                 }
97
98                 public string GetFullName ()
99                 {
100                         string full_name;
101                         if (TypeArguments != null)
102                                 full_name = Name + "<" + TypeArguments + ">";
103                         else
104                                 full_name = Name;
105                         if (Left != null)
106                                 return Left.GetFullName () + "." + full_name;
107                         else
108                                 return full_name;
109                 }
110
111                 public static string MakeName (string name, TypeArguments args)
112                 {
113                         if (args == null)
114                                 return name;
115                         else
116                                 return name + "`" + args.Count;
117                 }
118
119                 public static string MakeName (string name, int count)
120                 {
121                         return name + "`" + count;
122                 }
123
124                 public string GetTypeName ()
125                 {
126                         string suffix = "";
127                         if (Left != null)
128                                 return Left.GetTypeName () + "." +
129                                         MakeName (Name, TypeArguments);
130                         else
131                                 return MakeName (Name, TypeArguments);
132                 }
133
134                 protected bool IsUnbound {
135                         get {
136                                 if ((Left != null) && Left.IsUnbound)
137                                         return true;
138                                 else if (TypeArguments == null)
139                                         return false;
140                                 else
141                                         return TypeArguments.IsUnbound;
142                         }
143                 }
144
145                 protected bool CheckUnbound (Location loc)
146                 {
147                         if ((Left != null) && !Left.CheckUnbound (loc))
148                                 return false;
149                         if ((TypeArguments != null) && !TypeArguments.IsUnbound) {
150                                 Report.Error (1031, loc, "Type expected");
151                                 return false;
152                         }
153
154                         return true;
155                 }
156
157                 public Expression GetTypeExpression (Location loc)
158                 {
159                         if (IsUnbound) {
160                                 if (!CheckUnbound (loc))
161                                         return null;
162
163                                 return new UnboundTypeExpression (GetTypeName ());
164                         }
165
166                         if (Left != null) {
167                                 Expression lexpr = Left.GetTypeExpression (loc);
168
169                                 return new MemberAccess (lexpr, Name, TypeArguments, loc);
170                         } else {
171                                 if (TypeArguments != null)
172                                         return new ConstructedType (Name, TypeArguments, loc);
173                                 else
174                                         return new SimpleName (Name, loc);
175                         }
176                 }
177
178                 public string Basename {
179                         get {
180                                 if (TypeArguments != null)
181                                         return MakeName (Name, TypeArguments);
182                                 else
183                                         return Name;
184                         }
185                 }
186
187                 public override string ToString ()
188                 {
189                         string full_name;
190                         if (TypeArguments != null)
191                                 full_name = Name + "<" + TypeArguments + ">";
192                         else
193                                 full_name = Name;
194
195                         if (Left != null)
196                                 return Left + "." + full_name;
197                         else
198                                 return full_name;
199                 }
200         }
201
202         /// <summary>
203         ///   Base representation for members.  This is used to keep track
204         ///   of Name, Location and Modifier flags, and handling Attributes.
205         /// </summary>
206         public abstract class MemberCore : Attributable {
207                 /// <summary>
208                 ///   Public name
209                 /// </summary>
210                 public string Name;
211
212                 public readonly MemberName MemberName;
213
214                 /// <summary>
215                 ///   Modifier flags that the user specified in the source code
216                 /// </summary>
217                 public int ModFlags;
218
219                 public readonly TypeContainer Parent;
220
221                 /// <summary>
222                 ///   Location where this declaration happens
223                 /// </summary>
224                 public readonly Location Location;
225
226                 [Flags]
227                 public enum Flags {
228                         Obsolete_Undetected = 1,                // Obsolete attribute has not been detected yet
229                         Obsolete = 1 << 1,                      // Type has obsolete attribute
230                         ClsCompliance_Undetected = 1 << 2,      // CLS Compliance has not been detected yet
231                         ClsCompliant = 1 << 3,                  // Type is CLS Compliant
232                         CloseTypeCreated = 1 << 4,              // Tracks whether we have Closed the type
233                         HasCompliantAttribute_Undetected = 1 << 5,      // Presence of CLSCompliantAttribute has not been detected
234                         HasClsCompliantAttribute = 1 << 6,                      // Type has CLSCompliantAttribute
235                         ClsCompliantAttributeTrue = 1 << 7,                     // Type has CLSCompliant (true)
236                         Excluded_Undetected = 1 << 8,           // Conditional attribute has not been detected yet
237                         Excluded = 1 << 9                                       // Method is conditional
238
239                 }
240   
241                 /// <summary>
242                 ///   MemberCore flags at first detected then cached
243                 /// </summary>
244                 protected Flags caching_flags;
245
246                 public MemberCore (TypeContainer parent, MemberName name, Attributes attrs,
247                                    Location loc)
248                         : base (attrs)
249                 {
250                         Parent = parent;
251                         Name = name.GetName (!(this is GenericMethod) && !(this is Method));
252                         MemberName = name;
253                         Location = loc;
254                         caching_flags = Flags.Obsolete_Undetected | Flags.ClsCompliance_Undetected | Flags.HasCompliantAttribute_Undetected | Flags.Excluded_Undetected;
255                 }
256
257                 /// <summary>
258                 /// Tests presence of ObsoleteAttribute and report proper error
259                 /// </summary>
260                 protected void CheckUsageOfObsoleteAttribute (Type type)
261                 {
262                         if (type == null)
263                                 return;
264
265                         ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (type);
266                         if (obsolete_attr == null)
267                                 return;
268
269                         AttributeTester.Report_ObsoleteMessage (obsolete_attr, type.FullName, Location);
270                 }
271
272                 public abstract bool Define ();
273
274                 // 
275                 // Returns full member name for error message
276                 //
277                 public virtual string GetSignatureForError ()
278                 {
279                         return Name;
280                 }
281
282                 /// <summary>
283                 /// Base Emit method. This is also entry point for CLS-Compliant verification.
284                 /// </summary>
285                 public virtual void Emit ()
286                 {
287                         VerifyObsoleteAttribute ();
288
289                         if (!RootContext.VerifyClsCompliance)
290                                 return;
291
292                         VerifyClsCompliance (Parent);
293                 }
294
295                 // 
296                 // Whehter is it ok to use an unsafe pointer in this type container
297                 //
298                 public bool UnsafeOK (DeclSpace parent)
299                 {
300                         //
301                         // First check if this MemberCore modifier flags has unsafe set
302                         //
303                         if ((ModFlags & Modifiers.UNSAFE) != 0)
304                                 return true;
305
306                         if (parent.UnsafeContext)
307                                 return true;
308
309                         Expression.UnsafeError (Location);
310                         return false;
311                 }
312
313                 /// <summary>
314                 /// Returns instance of ObsoleteAttribute for this MemberCore
315                 /// </summary>
316                 public ObsoleteAttribute GetObsoleteAttribute (DeclSpace ds)
317                 {
318                         // ((flags & (Flags.Obsolete_Undetected | Flags.Obsolete)) == 0) is slower, but why ?
319                         if ((caching_flags & Flags.Obsolete_Undetected) == 0 && (caching_flags & Flags.Obsolete) == 0) {
320                                 return null;
321                         }
322
323                         caching_flags &= ~Flags.Obsolete_Undetected;
324
325                         if (OptAttributes == null)
326                                 return null;
327
328                         // TODO: remove this allocation
329                         EmitContext ec = new EmitContext (ds.Parent, ds, ds.Location,
330                                 null, null, ds.ModFlags, false);
331
332                         Attribute obsolete_attr = OptAttributes.Search (TypeManager.obsolete_attribute_type, ec);
333                         if (obsolete_attr == null)
334                                 return null;
335
336                         ObsoleteAttribute obsolete = obsolete_attr.GetObsoleteAttribute (ds);
337                         if (obsolete == null)
338                                 return null;
339
340                         caching_flags |= Flags.Obsolete;
341                         return obsolete;
342                 }
343
344                 /// <summary>
345                 /// Analyze whether CLS-Compliant verification must be execute for this MemberCore.
346                 /// </summary>
347                 public override bool IsClsCompliaceRequired (DeclSpace container)
348                 {
349                         if ((caching_flags & Flags.ClsCompliance_Undetected) == 0)
350                                 return (caching_flags & Flags.ClsCompliant) != 0;
351
352                         if (GetClsCompliantAttributeValue (container) && IsExposedFromAssembly (container)) {
353                                 caching_flags &= ~Flags.ClsCompliance_Undetected;
354                                 caching_flags |= Flags.ClsCompliant;
355                                 return true;
356                         }
357
358                         caching_flags &= ~Flags.ClsCompliance_Undetected;
359                         return false;
360                 }
361
362                 /// <summary>
363                 /// Returns true when MemberCore is exposed from assembly.
364                 /// </summary>
365                 protected bool IsExposedFromAssembly (DeclSpace ds)
366                 {
367                         if ((ModFlags & (Modifiers.PUBLIC | Modifiers.PROTECTED)) == 0)
368                                 return false;
369                         
370                         DeclSpace parentContainer = ds;
371                         while (parentContainer != null && parentContainer.ModFlags != 0) {
372                                 if ((parentContainer.ModFlags & (Modifiers.PUBLIC | Modifiers.PROTECTED)) == 0)
373                                         return false;
374                                 parentContainer = parentContainer.Parent;
375                         }
376                         return true;
377                 }
378
379                 /// <summary>
380                 /// Resolve CLSCompliantAttribute value or gets cached value.
381                 /// </summary>
382                 bool GetClsCompliantAttributeValue (DeclSpace ds)
383                 {
384                         if (OptAttributes != null) {
385                                 EmitContext ec = new EmitContext (ds.Parent, ds, ds.Location,
386                                                                   null, null, ds.ModFlags, false);
387                                 Attribute cls_attribute = OptAttributes.GetClsCompliantAttribute (ec);
388                                 if (cls_attribute != null) {
389                                         caching_flags |= Flags.HasClsCompliantAttribute;
390                                         return cls_attribute.GetClsCompliantAttributeValue (ds);
391                                 }
392                         }
393                         return ds.GetClsCompliantAttributeValue ();
394                 }
395
396                 /// <summary>
397                 /// Returns true if MemberCore is explicitly marked with CLSCompliantAttribute
398                 /// </summary>
399                 protected bool HasClsCompliantAttribute {
400                         get {
401                                 return (caching_flags & Flags.HasClsCompliantAttribute) != 0;
402                         }
403                 }
404
405                 /// <summary>
406                 /// The main virtual method for CLS-Compliant verifications.
407                 /// The method returns true if member is CLS-Compliant and false if member is not
408                 /// CLS-Compliant which means that CLS-Compliant tests are not necessary. A descendants override it
409                 /// and add their extra verifications.
410                 /// </summary>
411                 protected virtual bool VerifyClsCompliance (DeclSpace ds)
412                 {
413                         if (!IsClsCompliaceRequired (ds)) {
414                                 if ((RootContext.WarningLevel >= 2) && HasClsCompliantAttribute && !IsExposedFromAssembly (ds)) {
415                                         Report.Warning (3019, Location, "CLS compliance checking will not be performed on '{0}' because it is private or internal", GetSignatureForError ());
416                                 }
417                                 return false;
418                         }
419
420                         if (!CodeGen.Assembly.IsClsCompliant) {
421                                 if (HasClsCompliantAttribute) {
422                                         Report.Error (3014, Location, "'{0}' cannot be marked as CLS-compliant because the assembly does not have a CLSCompliant attribute", GetSignatureForError ());
423                                 }
424                         }
425
426                         int index = Name.LastIndexOf ('.');
427                         if (Name [index > 0 ? index + 1 : 0] == '_') {
428                                 Report.Error (3008, Location, "Identifier '{0}' is not CLS-compliant", GetSignatureForError () );
429                         }
430                         return true;
431                 }
432
433                 protected abstract void VerifyObsoleteAttribute ();
434
435         }
436
437         /// <summary>
438         ///   Base class for structs, classes, enumerations and interfaces.  
439         /// </summary>
440         /// <remarks>
441         ///   They all create new declaration spaces.  This
442         ///   provides the common foundation for managing those name
443         ///   spaces.
444         /// </remarks>
445         public abstract class DeclSpace : MemberCore, IAlias {
446                 /// <summary>
447                 ///   This points to the actual definition that is being
448                 ///   created with System.Reflection.Emit
449                 /// </summary>
450                 public TypeBuilder TypeBuilder;
451
452                 /// <summary>
453                 ///   If we are a generic type, this is the type we are
454                 ///   currently defining.  We need to lookup members on this
455                 ///   instead of the TypeBuilder.
456                 /// </summary>
457                 public TypeExpr CurrentType;
458
459                 //
460                 // This is the namespace in which this typecontainer
461                 // was declared.  We use this to resolve names.
462                 //
463                 public NamespaceEntry NamespaceEntry;
464
465                 public Hashtable Cache = new Hashtable ();
466                 
467                 public string Basename;
468                 
469                 /// <summary>
470                 ///   defined_names is used for toplevel objects
471                 /// </summary>
472                 protected Hashtable defined_names;
473
474                 readonly bool is_generic;
475                 readonly int count_type_params;
476
477                 //
478                 // Whether we are Generic
479                 //
480                 public bool IsGeneric {
481                         get {
482                                 if (is_generic)
483                                         return true;
484                                 else if (Parent != null)
485                                         return Parent.IsGeneric;
486                                 else
487                                         return false;
488                         }
489                 }
490
491                 static string[] attribute_targets = new string [] { "type" };
492
493                 public DeclSpace (NamespaceEntry ns, TypeContainer parent, MemberName name,
494                                   Attributes attrs, Location l)
495                         : base (parent, name, attrs, l)
496                 {
497                         NamespaceEntry = ns;
498                         Basename = name.Name;
499                         defined_names = new Hashtable ();
500                         if (name.TypeArguments != null) {
501                                 is_generic = true;
502                                 count_type_params = name.TypeArguments.Count;
503                         }
504                         if (parent != null)
505                                 count_type_params += parent.count_type_params;
506                 }
507
508                 public void RecordDecl ()
509                 {
510                         if ((NamespaceEntry != null) && (Parent == RootContext.Tree.Types))
511                                 NamespaceEntry.DefineName (MemberName.Basename, this);
512                 }
513
514                 /// <summary>
515                 ///   The result value from adding an declaration into
516                 ///   a struct or a class
517                 /// </summary>
518                 public enum AdditionResult {
519                         /// <summary>
520                         /// The declaration has been successfully
521                         /// added to the declation space.
522                         /// </summary>
523                         Success,
524
525                         /// <summary>
526                         ///   The symbol has already been defined.
527                         /// </summary>
528                         NameExists,
529
530                         /// <summary>
531                         ///   Returned if the declation being added to the
532                         ///   name space clashes with its container name.
533                         ///
534                         ///   The only exceptions for this are constructors
535                         ///   and static constructors
536                         /// </summary>
537                         EnclosingClash,
538
539                         /// <summary>
540                         ///   Returned if a constructor was created (because syntactically
541                         ///   it looked like a constructor) but was not (because the name
542                         ///   of the method is not the same as the container class
543                         /// </summary>
544                         NotAConstructor,
545
546                         /// <summary>
547                         ///   This is only used by static constructors to emit the
548                         ///   error 111, but this error for other things really
549                         ///   happens at another level for other functions.
550                         /// </summary>
551                         MethodExists,
552
553                         /// <summary>
554                         ///   Some other error.
555                         /// </summary>
556                         Error
557                 }
558
559                 /// <summary>
560                 ///   Returns a status code based purely on the name
561                 ///   of the member being added
562                 /// </summary>
563                 protected AdditionResult IsValid (string basename, string name)
564                 {
565                         if (basename == Basename)
566                                 return AdditionResult.EnclosingClash;
567
568                         if (defined_names.Contains (name))
569                                 return AdditionResult.NameExists;
570
571                         return AdditionResult.Success;
572                 }
573
574                 public static int length;
575                 public static int small;
576                 
577                 /// <summary>
578                 ///   Introduce @name into this declaration space and
579                 ///   associates it with the object @o.  Note that for
580                 ///   methods this will just point to the first method. o
581                 /// </summary>
582                 public void DefineName (string name, object o)
583                 {
584                         defined_names.Add (name, o);
585
586 #if DEBUGME
587                         int p = name.LastIndexOf ('.');
588                         int l = name.Length;
589                         length += l;
590                         small += l -p;
591 #endif
592                 }
593
594                 /// <summary>
595                 ///   Returns the object associated with a given name in the declaration
596                 ///   space.  This is the inverse operation of `DefineName'
597                 /// </summary>
598                 public object GetDefinition (string name)
599                 {
600                         return defined_names [name];
601                 }
602                 
603                 bool in_transit = false;
604                 
605                 /// <summary>
606                 ///   This function is used to catch recursive definitions
607                 ///   in declarations.
608                 /// </summary>
609                 public bool InTransit {
610                         get {
611                                 return in_transit;
612                         }
613
614                         set {
615                                 in_transit = value;
616                         }
617                 }
618
619                 /// <summary>
620                 ///   Looks up the alias for the name
621                 /// </summary>
622                 public IAlias LookupAlias (string name)
623                 {
624                         if (NamespaceEntry != null)
625                                 return NamespaceEntry.LookupAlias (name);
626                         else
627                                 return null;
628                 }
629                 
630                 // 
631                 // root_types contains all the types.  All TopLevel types
632                 // hence have a parent that points to `root_types', that is
633                 // why there is a non-obvious test down here.
634                 //
635                 public bool IsTopLevel {
636                         get {
637                                 if (Parent != null){
638                                         if (Parent.Parent == null)
639                                                 return true;
640                                 }
641                                 return false;
642                         }
643                 }
644
645                 public virtual void CloseType ()
646                 {
647                         if ((caching_flags & Flags.CloseTypeCreated) == 0){
648                                 try {
649                                         TypeBuilder.CreateType ();
650                                 } catch {
651                                         //
652                                         // The try/catch is needed because
653                                         // nested enumerations fail to load when they
654                                         // are defined.
655                                         //
656                                         // Even if this is the right order (enumerations
657                                         // declared after types).
658                                         //
659                                         // Note that this still creates the type and
660                                         // it is possible to save it
661                                 }
662                                 caching_flags |= Flags.CloseTypeCreated;
663                         }
664                 }
665
666                 /// <remarks>
667                 ///  Should be overriten by the appropriate declaration space
668                 /// </remarks>
669                 public abstract TypeBuilder DefineType ();
670                 
671                 /// <summary>
672                 ///   Define all members, but don't apply any attributes or do anything which may
673                 ///   access not-yet-defined classes.  This method also creates the MemberCache.
674                 /// </summary>
675                 public abstract bool DefineMembers (TypeContainer parent);
676
677                 //
678                 // Whether this is an `unsafe context'
679                 //
680                 public bool UnsafeContext {
681                         get {
682                                 if ((ModFlags & Modifiers.UNSAFE) != 0)
683                                         return true;
684                                 if (Parent != null)
685                                         return Parent.UnsafeContext;
686                                 return false;
687                         }
688                 }
689
690                 public static string MakeFQN (string nsn, string name)
691                 {
692                         if (nsn == "")
693                                 return name;
694                         return String.Concat (nsn, ".", name);
695                 }
696
697                 EmitContext type_resolve_ec;
698                 EmitContext GetTypeResolveEmitContext (TypeContainer parent, Location loc)
699                 {
700                         type_resolve_ec = new EmitContext (parent, this, loc, null, null, ModFlags, false);
701                         type_resolve_ec.ResolvingTypeTree = true;
702
703                         return type_resolve_ec;
704                 }
705
706                 // <summary>
707                 //    Looks up the type, as parsed into the expression `e' 
708                 // </summary>
709                 public Type ResolveType (Expression e, bool silent, Location loc)
710                 {
711                         TypeExpr d = ResolveTypeExpr (e, silent, loc);
712                         if (d == null)
713                                 return null;
714
715                         return ResolveType (d, loc);
716                 }
717
718                 public Type ResolveType (TypeExpr d, Location loc)
719                 {
720                         if (!d.CheckAccessLevel (this)) {
721                                 Report.Error (122, loc, "'{0}' is inaccessible due to its protection level", d.Name);
722                                 return null;
723                         }
724
725                         Type t = d.ResolveType (type_resolve_ec);
726                         if (t == null)
727                                 return null;
728
729                         if (d is UnboundTypeExpression)
730                                 return t;
731
732                         TypeContainer tc = TypeManager.LookupTypeContainer (t);
733                         if ((tc != null) && tc.IsGeneric) {
734                                 if (!IsGeneric) {
735                                         int tnum = TypeManager.GetNumberOfTypeArguments (t);
736                                         Report.Error (305, loc,
737                                                       "Using the generic type `{0}' " +
738                                                       "requires {1} type arguments",
739                                                       TypeManager.GetFullName (t), tnum);
740                                         return null;
741                                 }
742
743                                 ConstructedType ctype = new ConstructedType (
744                                         t, TypeParameters, loc);
745
746                                 t = ctype.ResolveType (type_resolve_ec);
747                         }
748
749                         return t;
750                 }
751
752                 // <summary>
753                 //    Resolves the expression `e' for a type, and will recursively define
754                 //    types. 
755                 // </summary>
756                 public TypeExpr ResolveTypeExpr (Expression e, bool silent, Location loc)
757                 {
758                         if (type_resolve_ec == null)
759                                 type_resolve_ec = GetTypeResolveEmitContext (Parent, loc);
760                         type_resolve_ec.loc = loc;
761                         if (this is GenericMethod)
762                                 type_resolve_ec.ContainerType = Parent.TypeBuilder;
763                         else
764                                 type_resolve_ec.ContainerType = TypeBuilder;
765
766                         int errors = Report.Errors;
767
768                         TypeExpr d = e.ResolveAsTypeTerminal (type_resolve_ec);
769
770                         if ((d != null) && (d.eclass == ExprClass.Type))
771                                 return d;
772
773                         if (silent || (Report.Errors != errors))
774                                 return null;
775
776                         if (e is SimpleName){
777                                 SimpleName s = new SimpleName (((SimpleName) e).Name, loc);
778                                 d = s.ResolveAsTypeTerminal (type_resolve_ec);
779
780                                 if ((d == null) || (d.Type == null)) {
781                                         Report.Error (246, loc, "Cannot find type `{0}'", e);
782                                         return null;
783                                 }
784
785                                 int num_args = TypeManager.GetNumberOfTypeArguments (d.Type);
786
787                                 if (num_args == 0) {
788                                         Report.Error (308, loc,
789                                                       "The non-generic type `{0}' cannot " +
790                                                       "be used with type arguments.",
791                                                       TypeManager.CSharpName (d.Type));
792                                         return null;
793                                 }
794
795                                 Report.Error (305, loc,
796                                               "Using the generic type `{0}' " +
797                                               "requires {1} type arguments",
798                                               TypeManager.GetFullName (d.Type), num_args);
799                                 return null;
800                         }
801
802                         Report.Error (246, loc, "Cannot find type `{0}'", e);
803                         return null;
804                 }
805                 
806                 public bool CheckAccessLevel (Type check_type) 
807                 {
808                         TypeBuilder tb;
809                         if (this is GenericMethod)
810                                 tb = Parent.TypeBuilder;
811                         else
812                                 tb = TypeBuilder;
813
814                         if (check_type.IsGenericInstance)
815                                 check_type = check_type.GetGenericTypeDefinition ();
816
817                         if (check_type == tb)
818                                 return true;
819
820                         if (check_type.IsGenericParameter)
821                                 return true; // FIXME
822                         
823                         TypeAttributes check_attr = check_type.Attributes & TypeAttributes.VisibilityMask;
824                         
825                         //
826                         // Broken Microsoft runtime, return public for arrays, no matter what 
827                         // the accessibility is for their underlying class, and they return 
828                         // NonPublic visibility for pointers
829                         //
830                         if (check_type.IsArray || check_type.IsPointer)
831                                 return CheckAccessLevel (TypeManager.GetElementType (check_type));
832
833                         switch (check_attr){
834                         case TypeAttributes.Public:
835                                 return true;
836
837                         case TypeAttributes.NotPublic:
838
839                                 // In same cases is null.
840                                 if (TypeBuilder == null)
841                                         return true;
842
843                                 //
844                                 // This test should probably use the declaringtype.
845                                 //
846                                 return check_type.Assembly == TypeBuilder.Assembly;
847
848                         case TypeAttributes.NestedPublic:
849                                 return true;
850
851                         case TypeAttributes.NestedPrivate:
852                                 string check_type_name = check_type.FullName;
853                                 string type_name = tb.FullName;
854
855                                 int cio = check_type_name.LastIndexOf ('+');
856                                 string container = check_type_name.Substring (0, cio);
857
858                                 //
859                                 // Check if the check_type is a nested class of the current type
860                                 //
861                                 if (check_type_name.StartsWith (type_name + "+")){
862                                         return true;
863                                 }
864                                 
865                                 if (type_name.StartsWith (container)){
866                                         return true;
867                                 }
868
869                                 return false;
870
871                         case TypeAttributes.NestedFamily:
872                                 //
873                                 // Only accessible to methods in current type or any subtypes
874                                 //
875                                 return FamilyAccessible (tb, check_type);
876
877                         case TypeAttributes.NestedFamANDAssem:
878                                 return (check_type.Assembly == tb.Assembly) &&
879                                         FamilyAccessible (tb, check_type);
880
881                         case TypeAttributes.NestedFamORAssem:
882                                 return (check_type.Assembly == tb.Assembly) ||
883                                         FamilyAccessible (tb, check_type);
884
885                         case TypeAttributes.NestedAssembly:
886                                 return check_type.Assembly == tb.Assembly;
887                         }
888
889                         Console.WriteLine ("HERE: " + check_attr);
890                         return false;
891
892                 }
893
894                 protected bool FamilyAccessible (TypeBuilder tb, Type check_type)
895                 {
896                         Type declaring = check_type.DeclaringType;
897                         if (tb.IsSubclassOf (declaring))
898                                 return true;
899
900                         string check_type_name = check_type.FullName;
901                         
902                         int cio = check_type_name.LastIndexOf ('+');
903                         string container = check_type_name.Substring (0, cio);
904                         
905                         //
906                         // Check if the check_type is a nested class of the current type
907                         //
908                         if (check_type_name.StartsWith (container + "+"))
909                                 return true;
910
911                         return false;
912                 }
913
914                 // Access level of a type.
915                 const int X = 1;
916                 enum AccessLevel { // Each column represents `is this scope larger or equal to Blah scope'
917                         // Public    Assembly   Protected
918                         Protected           = (0 << 0) | (0 << 1) | (X << 2),
919                         Public              = (X << 0) | (X << 1) | (X << 2),
920                         Private             = (0 << 0) | (0 << 1) | (0 << 2),
921                         Internal            = (0 << 0) | (X << 1) | (0 << 2),
922                         ProtectedOrInternal = (0 << 0) | (X << 1) | (X << 2),
923                 }
924
925                 static AccessLevel GetAccessLevelFromModifiers (int flags)
926                 {
927                         if ((flags & Modifiers.INTERNAL) != 0) {
928
929                                 if ((flags & Modifiers.PROTECTED) != 0)
930                                         return AccessLevel.ProtectedOrInternal;
931                                 else
932                                         return AccessLevel.Internal;
933
934                         } else if ((flags & Modifiers.PROTECTED) != 0)
935                                 return AccessLevel.Protected;
936                         else if ((flags & Modifiers.PRIVATE) != 0)
937                                 return AccessLevel.Private;
938                         else
939                                 return AccessLevel.Public;
940                 }
941
942                 // What is the effective access level of this?
943                 // TODO: Cache this?
944                 AccessLevel EffectiveAccessLevel {
945                         get {
946                                 AccessLevel myAccess = GetAccessLevelFromModifiers (ModFlags);
947                                 if (!IsTopLevel && (Parent != null))
948                                         return myAccess & Parent.EffectiveAccessLevel;
949                                 return myAccess;
950                         }
951                 }
952
953                 // Return the access level for type `t'
954                 static AccessLevel TypeEffectiveAccessLevel (Type t)
955                 {
956                         if (t.IsPublic)
957                                 return AccessLevel.Public;
958                         if (t.IsNestedPrivate)
959                                 return AccessLevel.Private;
960                         if (t.IsNotPublic)
961                                 return AccessLevel.Internal;
962
963                         // By now, it must be nested
964                         AccessLevel parentLevel = TypeEffectiveAccessLevel (t.DeclaringType);
965
966                         if (t.IsNestedPublic)
967                                 return parentLevel;
968                         if (t.IsNestedAssembly)
969                                 return parentLevel & AccessLevel.Internal;
970                         if (t.IsNestedFamily)
971                                 return parentLevel & AccessLevel.Protected;
972                         if (t.IsNestedFamORAssem)
973                                 return parentLevel & AccessLevel.ProtectedOrInternal;
974                         if (t.IsNestedFamANDAssem)
975                                 throw new NotImplementedException ("NestedFamANDAssem not implemented, cant make this kind of type from c# anyways");
976
977                         // nested private is taken care of
978
979                         throw new Exception ("I give up, what are you?");
980                 }
981
982                 //
983                 // This answers `is the type P, as accessible as a member M which has the
984                 // accessability @flags which is declared as a nested member of the type T, this declspace'
985                 //
986                 public bool AsAccessible (Type p, int flags)
987                 {
988                         if (p.IsGenericParameter)
989                                 return true; // FIXME
990
991                         //
992                         // 1) if M is private, its accessability is the same as this declspace.
993                         // we already know that P is accessible to T before this method, so we
994                         // may return true.
995                         //
996
997                         if ((flags & Modifiers.PRIVATE) != 0)
998                                 return true;
999
1000                         while (p.IsArray || p.IsPointer || p.IsByRef)
1001                                 p = TypeManager.GetElementType (p);
1002
1003                         AccessLevel pAccess = TypeEffectiveAccessLevel (p);
1004                         AccessLevel mAccess = this.EffectiveAccessLevel &
1005                                 GetAccessLevelFromModifiers (flags);
1006
1007                         // for every place from which we can access M, we must
1008                         // be able to access P as well. So, we want
1009                         // For every bit in M and P, M_i -> P_1 == true
1010                         // or, ~ (M -> P) == 0 <-> ~ ( ~M | P) == 0
1011
1012                         return ~ (~ mAccess | pAccess) == 0;
1013                 }
1014                 
1015                 static DoubleHash dh = new DoubleHash (1000);
1016
1017                 Type DefineTypeAndParents (DeclSpace tc)
1018                 {
1019                         DeclSpace container = tc.Parent;
1020
1021                         if (container.TypeBuilder == null && container.Name != "")
1022                                 DefineTypeAndParents (container);
1023
1024                         return tc.DefineType ();
1025                 }
1026                 
1027                 Type LookupInterfaceOrClass (string ns, string name, out bool error)
1028                 {
1029                         DeclSpace parent;
1030                         Type t;
1031                         object r;
1032                         
1033                         error = false;
1034
1035                         if (dh.Lookup (ns, name, out r))
1036                                 return (Type) r;
1037                         else {
1038                                 if (ns != ""){
1039                                         if (Namespace.IsNamespace (ns)){
1040                                                 string fullname = (ns != "") ? ns + "." + name : name;
1041                                                 t = TypeManager.LookupType (fullname);
1042                                         } else
1043                                                 t = null;
1044                                 } else
1045                                         t = TypeManager.LookupType (name);
1046                         }
1047                         
1048                         if (t != null) {
1049                                 dh.Insert (ns, name, t);
1050                                 return t;
1051                         }
1052
1053                         //
1054                         // In case we are fed a composite name, normalize it.
1055                         //
1056                         int p = name.LastIndexOf ('.');
1057                         if (p != -1){
1058                                 ns = MakeFQN (ns, name.Substring (0, p));
1059                                 name = name.Substring (p+1);
1060                         }
1061                         
1062                         parent = RootContext.Tree.LookupByNamespace (ns, name);
1063                         if (parent == null) {
1064                                 dh.Insert (ns, name, null);
1065                                 return null;
1066                         }
1067
1068                         t = DefineTypeAndParents (parent);
1069                         if (t == null){
1070                                 error = true;
1071                                 return null;
1072                         }
1073                         
1074                         dh.Insert (ns, name, t);
1075                         return t;
1076                 }
1077
1078                 public static void Error_AmbiguousTypeReference (Location loc, string name, string t1, string t2)
1079                 {
1080                         Report.Error (104, loc,
1081                                       "`{0}' is an ambiguous reference ({1} or {2})",
1082                                       name, t1, t2);
1083                 }
1084
1085                 public Type FindNestedType (Location loc, string name,
1086                                             out DeclSpace containing_ds)
1087                 {
1088                         Type t;
1089                         bool error;
1090
1091                         containing_ds = this;
1092                         while (containing_ds != null){
1093                                 Type container_type = containing_ds.TypeBuilder;
1094                                 Type current_type = container_type;
1095
1096                                 while (current_type != null && current_type != TypeManager.object_type) {
1097                                         string pre = current_type.FullName;
1098
1099                                         t = LookupInterfaceOrClass (pre, name, out error);
1100                                         if (error)
1101                                                 return null;
1102
1103                                         if ((t != null) && containing_ds.CheckAccessLevel (t))
1104                                                 return t;
1105
1106                                         current_type = current_type.BaseType;
1107                                 }
1108                                 containing_ds = containing_ds.Parent;
1109                         }
1110
1111                         return null;
1112                 }
1113
1114                 /// <summary>
1115                 ///   GetType is used to resolve type names at the DeclSpace level.
1116                 ///   Use this to lookup class/struct bases, interface bases or 
1117                 ///   delegate type references
1118                 /// </summary>
1119                 ///
1120                 /// <remarks>
1121                 ///   Contrast this to LookupType which is used inside method bodies to 
1122                 ///   lookup types that have already been defined.  GetType is used
1123                 ///   during the tree resolution process and potentially define
1124                 ///   recursively the type
1125                 /// </remarks>
1126                 public Type FindType (Location loc, string name)
1127                 {
1128                         Type t;
1129                         bool error;
1130
1131                         //
1132                         // For the case the type we are looking for is nested within this one
1133                         // or is in any base class
1134                         //
1135                         DeclSpace containing_ds = this;
1136
1137                         while (containing_ds != null){
1138                                 Type container_type = containing_ds.TypeBuilder;
1139                                 Type current_type = container_type;
1140
1141                                 while (current_type != null && current_type != TypeManager.object_type) {
1142                                         string pre = current_type.FullName;
1143
1144                                         t = LookupInterfaceOrClass (pre, name, out error);
1145                                         if (error)
1146                                                 return null;
1147
1148                                         if ((t != null) && containing_ds.CheckAccessLevel (t))
1149                                                 return t;
1150
1151                                         current_type = current_type.BaseType;
1152                                 }
1153                                 containing_ds = containing_ds.Parent;
1154                         }
1155
1156                         //
1157                         // Attempt to lookup the class on our namespace and all it's implicit parents
1158                         //
1159                         for (NamespaceEntry ns = NamespaceEntry; ns != null; ns = ns.ImplicitParent) {
1160                                 t = LookupInterfaceOrClass (ns.FullName, name, out error);
1161                                 if (error)
1162                                         return null;
1163
1164                                 if (t != null)
1165                                         return t;
1166                         }
1167                         
1168                         //
1169                         // Attempt to do a direct unqualified lookup
1170                         //
1171                         t = LookupInterfaceOrClass ("", name, out error);
1172                         if (error)
1173                                 return null;
1174                         
1175                         if (t != null)
1176                                 return t;
1177                         
1178                         //
1179                         // Attempt to lookup the class on any of the `using'
1180                         // namespaces
1181                         //
1182
1183                         for (NamespaceEntry ns = NamespaceEntry; ns != null; ns = ns.Parent){
1184
1185                                 t = LookupInterfaceOrClass (ns.FullName, name, out error);
1186                                 if (error)
1187                                         return null;
1188
1189                                 if (t != null)
1190                                         return t;
1191
1192                                 if (name.IndexOf ('.') > 0)
1193                                         continue;
1194
1195                                 IAlias alias_value = ns.LookupAlias (name);
1196                                 if (alias_value != null) {
1197                                         t = LookupInterfaceOrClass ("", alias_value.Name, out error);
1198                                         if (error)
1199                                                 return null;
1200
1201                                         if (t != null)
1202                                                 return t;
1203                                 }
1204
1205                                 //
1206                                 // Now check the using clause list
1207                                 //
1208                                 Type match = null;
1209                                 foreach (Namespace using_ns in ns.GetUsingTable ()) {
1210                                         match = LookupInterfaceOrClass (using_ns.Name, name, out error);
1211                                         if (error)
1212                                                 return null;
1213
1214                                         if (match != null) {
1215                                                 if (t != null){
1216                                                         if (CheckAccessLevel (match)) {
1217                                                                 Error_AmbiguousTypeReference (loc, name, t.FullName, match.FullName);
1218                                                                 return null;
1219                                                         }
1220                                                         continue;
1221                                                 }
1222                                                 
1223                                                 t = match;
1224                                         }
1225                                 }
1226                                 if (t != null)
1227                                         return t;
1228                         }
1229
1230                         //Report.Error (246, Location, "Can not find type `"+name+"'");
1231                         return null;
1232                 }
1233
1234                 /// <remarks>
1235                 ///   This function is broken and not what you're looking for.  It should only
1236                 ///   be used while the type is still being created since it doesn't use the cache
1237                 ///   and relies on the filter doing the member name check.
1238                 /// </remarks>
1239                 public abstract MemberList FindMembers (MemberTypes mt, BindingFlags bf,
1240                                                         MemberFilter filter, object criteria);
1241
1242                 /// <remarks>
1243                 ///   If we have a MemberCache, return it.  This property may return null if the
1244                 ///   class doesn't have a member cache or while it's still being created.
1245                 /// </remarks>
1246                 public abstract MemberCache MemberCache {
1247                         get;
1248                 }
1249
1250                 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
1251                 {
1252                         try {
1253                                 TypeBuilder.SetCustomAttribute (cb);
1254                         } catch (System.ArgumentException e) {
1255                                 Report.Warning (-21, a.Location,
1256                                                 "The CharSet named property on StructLayout\n"+
1257                                                 "\tdoes not work correctly on Microsoft.NET\n"+
1258                                                 "\tYou might want to remove the CharSet declaration\n"+
1259                                                 "\tor compile using the Mono runtime instead of the\n"+
1260                                                 "\tMicrosoft .NET runtime\n"+
1261                                                 "\tThe runtime gave the error: " + e);
1262                         }
1263                 }
1264
1265                 /// <summary>
1266                 /// Goes through class hierarchy and get value of first CLSCompliantAttribute that found.
1267                 /// If no is attribute exists then return assembly CLSCompliantAttribute.
1268                 /// </summary>
1269                 public bool GetClsCompliantAttributeValue ()
1270                 {
1271                         if ((caching_flags & Flags.HasCompliantAttribute_Undetected) == 0)
1272                                 return (caching_flags & Flags.ClsCompliantAttributeTrue) != 0;
1273
1274                         caching_flags &= ~Flags.HasCompliantAttribute_Undetected;
1275
1276                         if (OptAttributes != null) {
1277                                 EmitContext ec = new EmitContext (Parent, this, Location,
1278                                                                   null, null, ModFlags, false);
1279                                 Attribute cls_attribute = OptAttributes.GetClsCompliantAttribute (ec);
1280                                 if (cls_attribute != null) {
1281                                         caching_flags |= Flags.HasClsCompliantAttribute;
1282                                         if (cls_attribute.GetClsCompliantAttributeValue (this)) {
1283                                                 caching_flags |= Flags.ClsCompliantAttributeTrue;
1284                                                 return true;
1285                                         }
1286                                         return false;
1287                                 }
1288                         }
1289
1290                         if (Parent == null) {
1291                                 if (CodeGen.Assembly.IsClsCompliant) {
1292                                         caching_flags |= Flags.ClsCompliantAttributeTrue;
1293                                         return true;
1294                                 }
1295                                 return false;
1296                         }
1297
1298                         if (Parent.GetClsCompliantAttributeValue ()) {
1299                                 caching_flags |= Flags.ClsCompliantAttributeTrue;
1300                                 return true;
1301                         }
1302                         return false;
1303                 }
1304
1305                 //
1306                 // Extensions for generics
1307                 //
1308                 TypeParameter[] type_params;
1309                 TypeParameter[] type_param_list;
1310
1311                 protected string GetInstantiationName ()
1312                 {
1313                         StringBuilder sb = new StringBuilder (Name);
1314                         sb.Append ("<");
1315                         for (int i = 0; i < type_param_list.Length; i++) {
1316                                 if (i > 0)
1317                                         sb.Append (",");
1318                                 sb.Append (type_param_list [i].Name);
1319                         }
1320                         sb.Append (">");
1321                         return sb.ToString ();
1322                 }
1323
1324                 bool check_type_parameter (ArrayList list, int start, string name)
1325                 {
1326                         for (int i = 0; i < start; i++) {
1327                                 TypeParameter param = (TypeParameter) list [i];
1328
1329                                 if (param.Name != name)
1330                                         continue;
1331
1332                                 if (RootContext.WarningLevel >= 3)
1333                                         Report.Warning (
1334                                                 693, Location,
1335                                                 "Type parameter `{0}' has same name " +
1336                                                 "as type parameter from outer type `{1}'",
1337                                                 name, Parent.GetInstantiationName ());
1338
1339                                 return false;
1340                         }
1341
1342                         return true;
1343                 }
1344
1345                 TypeParameter[] initialize_type_params ()
1346                 {
1347                         if (type_param_list != null)
1348                                 return type_param_list;
1349
1350                         DeclSpace the_parent = Parent;
1351                         if (this is GenericMethod)
1352                                 the_parent = null;
1353
1354                         int start = 0;
1355                         TypeParameter[] parent_params = null;
1356                         if ((the_parent != null) && the_parent.IsGeneric) {
1357                                 parent_params = the_parent.initialize_type_params ();
1358                                 start = parent_params != null ? parent_params.Length : 0;
1359                         }
1360
1361                         ArrayList list = new ArrayList ();
1362                         if (parent_params != null)
1363                                 list.AddRange (parent_params);
1364
1365                         int count = type_params != null ? type_params.Length : 0;
1366                         for (int i = 0; i < count; i++) {
1367                                 TypeParameter param = type_params [i];
1368                                 check_type_parameter (list, start, param.Name);
1369                                 list.Add (param);
1370                         }
1371
1372                         type_param_list = new TypeParameter [list.Count];
1373                         list.CopyTo (type_param_list, 0);
1374                         return type_param_list;
1375                 }
1376
1377                 public AdditionResult SetParameterInfo (ArrayList constraints_list)
1378                 {
1379                         if (!is_generic) {
1380                                 if (constraints_list != null) {
1381                                         Report.Error (
1382                                                 80, Location, "Contraints are not allowed " +
1383                                                 "on non-generic declarations");
1384                                         return AdditionResult.Error;
1385                                 }
1386
1387                                 return AdditionResult.Success;
1388                         }
1389
1390                         string[] names = MemberName.TypeArguments.GetDeclarations ();
1391                         type_params = new TypeParameter [names.Length];
1392
1393                         //
1394                         // Register all the names
1395                         //
1396                         for (int i = 0; i < type_params.Length; i++) {
1397                                 string name = names [i];
1398
1399                                 AdditionResult res = IsValid (name, name);
1400
1401                                 if (res != AdditionResult.Success)
1402                                         return res;
1403
1404                                 Constraints constraints = null;
1405                                 if (constraints_list != null) {
1406                                         foreach (Constraints constraint in constraints_list) {
1407                                                 if (constraint.TypeParameter == name) {
1408                                                         constraints = constraint;
1409                                                         break;
1410                                                 }
1411                                         }
1412                                 }
1413
1414                                 type_params [i] = new TypeParameter (name, constraints, Location);
1415
1416                                 DefineName (name, type_params [i]);
1417                         }
1418
1419                         return AdditionResult.Success;
1420                 }
1421
1422                 public TypeParameter[] TypeParameters {
1423                         get {
1424                                 if (!IsGeneric)
1425                                         throw new InvalidOperationException ();
1426                                 if (type_param_list == null)
1427                                         initialize_type_params ();
1428
1429                                 return type_param_list;
1430                         }
1431                 }
1432
1433                 protected TypeParameter[] CurrentTypeParameters {
1434                         get {
1435                                 if (!IsGeneric)
1436                                         throw new InvalidOperationException ();
1437                                 if (type_params != null)
1438                                         return type_params;
1439                                 else
1440                                         return new TypeParameter [0];
1441                         }
1442                 }
1443
1444                 public int CountTypeParameters {
1445                         get {
1446                                 return count_type_params;
1447                         }
1448                 }
1449
1450                 public TypeParameterExpr LookupGeneric (string name, Location loc)
1451                 {
1452                         if (!IsGeneric)
1453                                 return null;
1454
1455                         foreach (TypeParameter type_param in CurrentTypeParameters) {
1456                                 if (type_param.Name != name)
1457                                         continue;
1458
1459                                 return new TypeParameterExpr (type_param, loc);
1460                         }
1461
1462                         if (Parent != null)
1463                                 return Parent.LookupGeneric (name, loc);
1464
1465                         return null;
1466                 }
1467
1468                 bool IAlias.IsType {
1469                         get { return true; }
1470                 }
1471
1472                 string IAlias.Name {
1473                         get { return Name; }
1474                 }
1475
1476                 TypeExpr IAlias.Type
1477                 {
1478                         get {
1479                                 if (TypeBuilder == null)
1480                                         throw new InvalidOperationException ();
1481
1482                                 if (CurrentType != null)
1483                                         return CurrentType;
1484
1485                                 return new TypeExpression (TypeBuilder, Location);
1486                         }
1487                 }
1488
1489                 public override string[] ValidAttributeTargets {
1490                         get {
1491                                 return attribute_targets;
1492                         }
1493                 }
1494         }
1495
1496         /// <summary>
1497         ///   This is a readonly list of MemberInfo's.      
1498         /// </summary>
1499         public class MemberList : IList {
1500                 public readonly IList List;
1501                 int count;
1502
1503                 /// <summary>
1504                 ///   Create a new MemberList from the given IList.
1505                 /// </summary>
1506                 public MemberList (IList list)
1507                 {
1508                         if (list != null)
1509                                 this.List = list;
1510                         else
1511                                 this.List = new ArrayList ();
1512                         count = List.Count;
1513                 }
1514
1515                 /// <summary>
1516                 ///   Concatenate the ILists `first' and `second' to a new MemberList.
1517                 /// </summary>
1518                 public MemberList (IList first, IList second)
1519                 {
1520                         ArrayList list = new ArrayList ();
1521                         list.AddRange (first);
1522                         list.AddRange (second);
1523                         count = list.Count;
1524                         List = list;
1525                 }
1526
1527                 public static readonly MemberList Empty = new MemberList (new ArrayList ());
1528
1529                 /// <summary>
1530                 ///   Cast the MemberList into a MemberInfo[] array.
1531                 /// </summary>
1532                 /// <remarks>
1533                 ///   This is an expensive operation, only use it if it's really necessary.
1534                 /// </remarks>
1535                 public static explicit operator MemberInfo [] (MemberList list)
1536                 {
1537                         Timer.StartTimer (TimerType.MiscTimer);
1538                         MemberInfo [] result = new MemberInfo [list.Count];
1539                         list.CopyTo (result, 0);
1540                         Timer.StopTimer (TimerType.MiscTimer);
1541                         return result;
1542                 }
1543
1544                 // ICollection
1545
1546                 public int Count {
1547                         get {
1548                                 return count;
1549                         }
1550                 }
1551
1552                 public bool IsSynchronized {
1553                         get {
1554                                 return List.IsSynchronized;
1555                         }
1556                 }
1557
1558                 public object SyncRoot {
1559                         get {
1560                                 return List.SyncRoot;
1561                         }
1562                 }
1563
1564                 public void CopyTo (Array array, int index)
1565                 {
1566                         List.CopyTo (array, index);
1567                 }
1568
1569                 // IEnumerable
1570
1571                 public IEnumerator GetEnumerator ()
1572                 {
1573                         return List.GetEnumerator ();
1574                 }
1575
1576                 // IList
1577
1578                 public bool IsFixedSize {
1579                         get {
1580                                 return true;
1581                         }
1582                 }
1583
1584                 public bool IsReadOnly {
1585                         get {
1586                                 return true;
1587                         }
1588                 }
1589
1590                 object IList.this [int index] {
1591                         get {
1592                                 return List [index];
1593                         }
1594
1595                         set {
1596                                 throw new NotSupportedException ();
1597                         }
1598                 }
1599
1600                 // FIXME: try to find out whether we can avoid the cast in this indexer.
1601                 public MemberInfo this [int index] {
1602                         get {
1603                                 return (MemberInfo) List [index];
1604                         }
1605                 }
1606
1607                 public int Add (object value)
1608                 {
1609                         throw new NotSupportedException ();
1610                 }
1611
1612                 public void Clear ()
1613                 {
1614                         throw new NotSupportedException ();
1615                 }
1616
1617                 public bool Contains (object value)
1618                 {
1619                         return List.Contains (value);
1620                 }
1621
1622                 public int IndexOf (object value)
1623                 {
1624                         return List.IndexOf (value);
1625                 }
1626
1627                 public void Insert (int index, object value)
1628                 {
1629                         throw new NotSupportedException ();
1630                 }
1631
1632                 public void Remove (object value)
1633                 {
1634                         throw new NotSupportedException ();
1635                 }
1636
1637                 public void RemoveAt (int index)
1638                 {
1639                         throw new NotSupportedException ();
1640                 }
1641         }
1642
1643         /// <summary>
1644         ///   This interface is used to get all members of a class when creating the
1645         ///   member cache.  It must be implemented by all DeclSpace derivatives which
1646         ///   want to support the member cache and by TypeHandle to get caching of
1647         ///   non-dynamic types.
1648         /// </summary>
1649         public interface IMemberContainer {
1650                 /// <summary>
1651                 ///   The name of the IMemberContainer.  This is only used for
1652                 ///   debugging purposes.
1653                 /// </summary>
1654                 string Name {
1655                         get;
1656                 }
1657
1658                 /// <summary>
1659                 ///   The type of this IMemberContainer.
1660                 /// </summary>
1661                 Type Type {
1662                         get;
1663                 }
1664
1665                 /// <summary>
1666                 ///   Returns the IMemberContainer of the parent class or null if this
1667                 ///   is an interface or TypeManger.object_type.
1668                 ///   This is used when creating the member cache for a class to get all
1669                 ///   members from the parent class.
1670                 /// </summary>
1671                 IMemberContainer ParentContainer {
1672                         get;
1673                 }
1674
1675                 /// <summary>
1676                 ///   Whether this is an interface.
1677                 /// </summary>
1678                 bool IsInterface {
1679                         get;
1680                 }
1681
1682                 /// <summary>
1683                 ///   Returns all members of this class with the corresponding MemberTypes
1684                 ///   and BindingFlags.
1685                 /// </summary>
1686                 /// <remarks>
1687                 ///   When implementing this method, make sure not to return any inherited
1688                 ///   members and check the MemberTypes and BindingFlags properly.
1689                 ///   Unfortunately, System.Reflection is lame and doesn't provide a way to
1690                 ///   get the BindingFlags (static/non-static,public/non-public) in the
1691                 ///   MemberInfo class, but the cache needs this information.  That's why
1692                 ///   this method is called multiple times with different BindingFlags.
1693                 /// </remarks>
1694                 MemberList GetMembers (MemberTypes mt, BindingFlags bf);
1695
1696                 /// <summary>
1697                 ///   Return the container's member cache.
1698                 /// </summary>
1699                 MemberCache MemberCache {
1700                         get;
1701                 }
1702         }
1703
1704         /// <summary>
1705         ///   The MemberCache is used by dynamic and non-dynamic types to speed up
1706         ///   member lookups.  It has a member name based hash table; it maps each member
1707         ///   name to a list of CacheEntry objects.  Each CacheEntry contains a MemberInfo
1708         ///   and the BindingFlags that were initially used to get it.  The cache contains
1709         ///   all members of the current class and all inherited members.  If this cache is
1710         ///   for an interface types, it also contains all inherited members.
1711         ///
1712         ///   There are two ways to get a MemberCache:
1713         ///   * if this is a dynamic type, lookup the corresponding DeclSpace and then
1714         ///     use the DeclSpace.MemberCache property.
1715         ///   * if this not a dynamic type, call TypeHandle.GetTypeHandle() to get a
1716         ///     TypeHandle instance for the type and then use TypeHandle.MemberCache.
1717         /// </summary>
1718         public class MemberCache {
1719                 public readonly IMemberContainer Container;
1720                 protected Hashtable member_hash;
1721                 protected Hashtable method_hash;
1722                 
1723                 /// <summary>
1724                 ///   Create a new MemberCache for the given IMemberContainer `container'.
1725                 /// </summary>
1726                 public MemberCache (IMemberContainer container)
1727                 {
1728                         this.Container = container;
1729
1730                         Timer.IncrementCounter (CounterType.MemberCache);
1731                         Timer.StartTimer (TimerType.CacheInit);
1732
1733                         
1734
1735                         // If we have a parent class (we have a parent class unless we're
1736                         // TypeManager.object_type), we deep-copy its MemberCache here.
1737                         if (Container.IsInterface) {
1738                                 MemberCache parent;
1739                                 
1740                                 if (Container.ParentContainer != null)
1741                                         parent = Container.ParentContainer.MemberCache;
1742                                 else
1743                                         parent = TypeHandle.ObjectType.MemberCache;
1744                                 member_hash = SetupCacheForInterface (parent);
1745                         } else if (Container.ParentContainer != null)
1746                                 member_hash = SetupCache (Container.ParentContainer.MemberCache);
1747                         else
1748                                 member_hash = new Hashtable ();
1749
1750                         // If this is neither a dynamic type nor an interface, create a special
1751                         // method cache with all declared and inherited methods.
1752                         Type type = container.Type;
1753                         if (!(type is TypeBuilder) && !type.IsInterface && !type.IsGenericParameter) {
1754                                 method_hash = new Hashtable ();
1755                                 AddMethods (type);
1756                         }
1757
1758                         // Add all members from the current class.
1759                         AddMembers (Container);
1760
1761                         Timer.StopTimer (TimerType.CacheInit);
1762                 }
1763
1764                 /// <summary>
1765                 ///   Bootstrap this member cache by doing a deep-copy of our parent.
1766                 /// </summary>
1767                 Hashtable SetupCache (MemberCache parent)
1768                 {
1769                         Hashtable hash = new Hashtable ();
1770
1771                         IDictionaryEnumerator it = parent.member_hash.GetEnumerator ();
1772                         while (it.MoveNext ()) {
1773                                 hash [it.Key] = ((ArrayList) it.Value).Clone ();
1774                         }
1775                                 
1776                         return hash;
1777                 }
1778
1779
1780                 /// <summary>
1781                 ///   Add the contents of `new_hash' to `hash'.
1782                 /// </summary>
1783                 void AddHashtable (Hashtable hash, MemberCache cache)
1784                 {
1785                         Hashtable new_hash = cache.member_hash;
1786                         IDictionaryEnumerator it = new_hash.GetEnumerator ();
1787                         while (it.MoveNext ()) {
1788                                 ArrayList list = (ArrayList) hash [it.Key];
1789                                 if (list == null)
1790                                         hash [it.Key] = list = new ArrayList ();
1791
1792                                 foreach (CacheEntry entry in (ArrayList) it.Value) {
1793                                         if (entry.Container != cache.Container)
1794                                                 break;
1795                                         list.Add (entry);
1796                                 }
1797                         }
1798                 }
1799
1800                 /// <summary>
1801                 ///   Bootstrap the member cache for an interface type.
1802                 ///   Type.GetMembers() won't return any inherited members for interface types,
1803                 ///   so we need to do this manually.  Interfaces also inherit from System.Object.
1804                 /// </summary>
1805                 Hashtable SetupCacheForInterface (MemberCache parent)
1806                 {
1807                         Hashtable hash = SetupCache (parent);
1808                         Type [] ifaces = TypeManager.GetInterfaces (Container.Type);
1809
1810                         foreach (Type itype in ifaces) {
1811                                 IMemberContainer iface_container =
1812                                         TypeManager.LookupMemberContainer (itype);
1813
1814                                 MemberCache iface_cache = iface_container.MemberCache;
1815
1816                                 AddHashtable (hash, iface_cache);
1817                         }
1818
1819                         return hash;
1820                 }
1821
1822                 /// <summary>
1823                 ///   Add all members from class `container' to the cache.
1824                 /// </summary>
1825                 void AddMembers (IMemberContainer container)
1826                 {
1827                         // We need to call AddMembers() with a single member type at a time
1828                         // to get the member type part of CacheEntry.EntryType right.
1829                         AddMembers (MemberTypes.Constructor, container);
1830                         AddMembers (MemberTypes.Field, container);
1831                         AddMembers (MemberTypes.Method, container);
1832                         AddMembers (MemberTypes.Property, container);
1833                         AddMembers (MemberTypes.Event, container);
1834                         // Nested types are returned by both Static and Instance searches.
1835                         AddMembers (MemberTypes.NestedType,
1836                                     BindingFlags.Static | BindingFlags.Public, container);
1837                         AddMembers (MemberTypes.NestedType,
1838                                     BindingFlags.Static | BindingFlags.NonPublic, container);
1839                 }
1840
1841                 void AddMembers (MemberTypes mt, IMemberContainer container)
1842                 {
1843                         AddMembers (mt, BindingFlags.Static | BindingFlags.Public, container);
1844                         AddMembers (mt, BindingFlags.Static | BindingFlags.NonPublic, container);
1845                         AddMembers (mt, BindingFlags.Instance | BindingFlags.Public, container);
1846                         AddMembers (mt, BindingFlags.Instance | BindingFlags.NonPublic, container);
1847                 }
1848
1849                 /// <summary>
1850                 ///   Add all members from class `container' with the requested MemberTypes and
1851                 ///   BindingFlags to the cache.  This method is called multiple times with different
1852                 ///   MemberTypes and BindingFlags.
1853                 /// </summary>
1854                 void AddMembers (MemberTypes mt, BindingFlags bf, IMemberContainer container)
1855                 {
1856                         MemberList members = container.GetMembers (mt, bf);
1857
1858                         foreach (MemberInfo member in members) {
1859                                 string name = member.Name;
1860
1861                                 int pos = name.IndexOf ('<');
1862                                 if (pos > 0)
1863                                         name = name.Substring (0, pos);
1864
1865                                 // We use a name-based hash table of ArrayList's.
1866                                 ArrayList list = (ArrayList) member_hash [name];
1867                                 if (list == null) {
1868                                         list = new ArrayList ();
1869                                         member_hash.Add (name, list);
1870                                 }
1871
1872                                 // When this method is called for the current class, the list will
1873                                 // already contain all inherited members from our parent classes.
1874                                 // We cannot add new members in front of the list since this'd be an
1875                                 // expensive operation, that's why the list is sorted in reverse order
1876                                 // (ie. members from the current class are coming last).
1877                                 list.Add (new CacheEntry (container, member, mt, bf));
1878                         }
1879                 }
1880
1881                 /// <summary>
1882                 ///   Add all declared and inherited methods from class `type' to the method cache.
1883                 /// </summary>
1884                 void AddMethods (Type type)
1885                 {
1886                         AddMethods (BindingFlags.Static | BindingFlags.Public |
1887                                     BindingFlags.FlattenHierarchy, type);
1888                         AddMethods (BindingFlags.Static | BindingFlags.NonPublic |
1889                                     BindingFlags.FlattenHierarchy, type);
1890                         AddMethods (BindingFlags.Instance | BindingFlags.Public, type);
1891                         AddMethods (BindingFlags.Instance | BindingFlags.NonPublic, type);
1892                 }
1893
1894                 void AddMethods (BindingFlags bf, Type type)
1895                 {
1896                         MemberInfo [] members = type.GetMethods (bf);
1897
1898                         Array.Reverse (members);
1899
1900                         foreach (MethodBase member in members) {
1901                                 string name = member.Name;
1902
1903                                 // We use a name-based hash table of ArrayList's.
1904                                 ArrayList list = (ArrayList) method_hash [name];
1905                                 if (list == null) {
1906                                         list = new ArrayList ();
1907                                         method_hash.Add (name, list);
1908                                 }
1909
1910                                 // Unfortunately, the elements returned by Type.GetMethods() aren't
1911                                 // sorted so we need to do this check for every member.
1912                                 BindingFlags new_bf = bf;
1913                                 if (member.DeclaringType == type)
1914                                         new_bf |= BindingFlags.DeclaredOnly;
1915
1916                                 list.Add (new CacheEntry (Container, member, MemberTypes.Method, new_bf));
1917                         }
1918                 }
1919
1920                 /// <summary>
1921                 ///   Compute and return a appropriate `EntryType' magic number for the given
1922                 ///   MemberTypes and BindingFlags.
1923                 /// </summary>
1924                 protected static EntryType GetEntryType (MemberTypes mt, BindingFlags bf)
1925                 {
1926                         EntryType type = EntryType.None;
1927
1928                         if ((mt & MemberTypes.Constructor) != 0)
1929                                 type |= EntryType.Constructor;
1930                         if ((mt & MemberTypes.Event) != 0)
1931                                 type |= EntryType.Event;
1932                         if ((mt & MemberTypes.Field) != 0)
1933                                 type |= EntryType.Field;
1934                         if ((mt & MemberTypes.Method) != 0)
1935                                 type |= EntryType.Method;
1936                         if ((mt & MemberTypes.Property) != 0)
1937                                 type |= EntryType.Property;
1938                         // Nested types are returned by static and instance searches.
1939                         if ((mt & MemberTypes.NestedType) != 0)
1940                                 type |= EntryType.NestedType | EntryType.Static | EntryType.Instance;
1941
1942                         if ((bf & BindingFlags.Instance) != 0)
1943                                 type |= EntryType.Instance;
1944                         if ((bf & BindingFlags.Static) != 0)
1945                                 type |= EntryType.Static;
1946                         if ((bf & BindingFlags.Public) != 0)
1947                                 type |= EntryType.Public;
1948                         if ((bf & BindingFlags.NonPublic) != 0)
1949                                 type |= EntryType.NonPublic;
1950                         if ((bf & BindingFlags.DeclaredOnly) != 0)
1951                                 type |= EntryType.Declared;
1952
1953                         return type;
1954                 }
1955
1956                 /// <summary>
1957                 ///   The `MemberTypes' enumeration type is a [Flags] type which means that it may
1958                 ///   denote multiple member types.  Returns true if the given flags value denotes a
1959                 ///   single member types.
1960                 /// </summary>
1961                 public static bool IsSingleMemberType (MemberTypes mt)
1962                 {
1963                         switch (mt) {
1964                         case MemberTypes.Constructor:
1965                         case MemberTypes.Event:
1966                         case MemberTypes.Field:
1967                         case MemberTypes.Method:
1968                         case MemberTypes.Property:
1969                         case MemberTypes.NestedType:
1970                                 return true;
1971
1972                         default:
1973                                 return false;
1974                         }
1975                 }
1976
1977                 /// <summary>
1978                 ///   We encode the MemberTypes and BindingFlags of each members in a "magic"
1979                 ///   number to speed up the searching process.
1980                 /// </summary>
1981                 [Flags]
1982                 protected enum EntryType {
1983                         None            = 0x000,
1984
1985                         Instance        = 0x001,
1986                         Static          = 0x002,
1987                         MaskStatic      = Instance|Static,
1988
1989                         Public          = 0x004,
1990                         NonPublic       = 0x008,
1991                         MaskProtection  = Public|NonPublic,
1992
1993                         Declared        = 0x010,
1994
1995                         Constructor     = 0x020,
1996                         Event           = 0x040,
1997                         Field           = 0x080,
1998                         Method          = 0x100,
1999                         Property        = 0x200,
2000                         NestedType      = 0x400,
2001
2002                         MaskType        = Constructor|Event|Field|Method|Property|NestedType
2003                 }
2004
2005                 protected struct CacheEntry {
2006                         public readonly IMemberContainer Container;
2007                         public readonly EntryType EntryType;
2008                         public readonly MemberInfo Member;
2009
2010                         public CacheEntry (IMemberContainer container, MemberInfo member,
2011                                            MemberTypes mt, BindingFlags bf)
2012                         {
2013                                 this.Container = container;
2014                                 this.Member = member;
2015                                 this.EntryType = GetEntryType (mt, bf);
2016                         }
2017                 }
2018
2019                 /// <summary>
2020                 ///   This is called each time we're walking up one level in the class hierarchy
2021                 ///   and checks whether we can abort the search since we've already found what
2022                 ///   we were looking for.
2023                 /// </summary>
2024                 protected bool DoneSearching (ArrayList list)
2025                 {
2026                         //
2027                         // We've found exactly one member in the current class and it's not
2028                         // a method or constructor.
2029                         //
2030                         if (list.Count == 1 && !(list [0] is MethodBase))
2031                                 return true;
2032
2033                         //
2034                         // Multiple properties: we query those just to find out the indexer
2035                         // name
2036                         //
2037                         if ((list.Count > 0) && (list [0] is PropertyInfo))
2038                                 return true;
2039
2040                         return false;
2041                 }
2042
2043                 /// <summary>
2044                 ///   Looks up members with name `name'.  If you provide an optional
2045                 ///   filter function, it'll only be called with members matching the
2046                 ///   requested member name.
2047                 ///
2048                 ///   This method will try to use the cache to do the lookup if possible.
2049                 ///
2050                 ///   Unlike other FindMembers implementations, this method will always
2051                 ///   check all inherited members - even when called on an interface type.
2052                 ///
2053                 ///   If you know that you're only looking for methods, you should use
2054                 ///   MemberTypes.Method alone since this speeds up the lookup a bit.
2055                 ///   When doing a method-only search, it'll try to use a special method
2056                 ///   cache (unless it's a dynamic type or an interface) and the returned
2057                 ///   MemberInfo's will have the correct ReflectedType for inherited methods.
2058                 ///   The lookup process will automatically restart itself in method-only
2059                 ///   search mode if it discovers that it's about to return methods.
2060                 /// </summary>
2061                 ArrayList global = new ArrayList ();
2062                 bool using_global = false;
2063                 
2064                 static MemberInfo [] emptyMemberInfo = new MemberInfo [0];
2065                 
2066                 public MemberInfo [] FindMembers (MemberTypes mt, BindingFlags bf, string name,
2067                                                MemberFilter filter, object criteria)
2068                 {
2069                         if (using_global)
2070                                 throw new Exception ();
2071                         
2072                         bool declared_only = (bf & BindingFlags.DeclaredOnly) != 0;
2073                         bool method_search = mt == MemberTypes.Method;
2074                         // If we have a method cache and we aren't already doing a method-only search,
2075                         // then we restart a method search if the first match is a method.
2076                         bool do_method_search = !method_search && (method_hash != null);
2077
2078                         ArrayList applicable;
2079
2080                         // If this is a method-only search, we try to use the method cache if
2081                         // possible; a lookup in the method cache will return a MemberInfo with
2082                         // the correct ReflectedType for inherited methods.
2083                         
2084                         if (method_search && (method_hash != null))
2085                                 applicable = (ArrayList) method_hash [name];
2086                         else
2087                                 applicable = (ArrayList) member_hash [name];
2088
2089                         if (applicable == null)
2090                                 return emptyMemberInfo;
2091
2092                         //
2093                         // 32  slots gives 53 rss/54 size
2094                         // 2/4 slots gives 55 rss
2095                         //
2096                         // Strange: from 25,000 calls, only 1,800
2097                         // are above 2.  Why does this impact it?
2098                         //
2099                         global.Clear ();
2100                         using_global = true;
2101
2102                         Timer.StartTimer (TimerType.CachedLookup);
2103
2104                         EntryType type = GetEntryType (mt, bf);
2105
2106                         IMemberContainer current = Container;
2107
2108
2109                         // `applicable' is a list of all members with the given member name `name'
2110                         // in the current class and all its parent classes.  The list is sorted in
2111                         // reverse order due to the way how the cache is initialy created (to speed
2112                         // things up, we're doing a deep-copy of our parent).
2113
2114                         for (int i = applicable.Count-1; i >= 0; i--) {
2115                                 CacheEntry entry = (CacheEntry) applicable [i];
2116
2117                                 // This happens each time we're walking one level up in the class
2118                                 // hierarchy.  If we're doing a DeclaredOnly search, we must abort
2119                                 // the first time this happens (this may already happen in the first
2120                                 // iteration of this loop if there are no members with the name we're
2121                                 // looking for in the current class).
2122                                 if (entry.Container != current) {
2123                                         if (declared_only || DoneSearching (global))
2124                                                 break;
2125
2126                                         current = entry.Container;
2127                                 }
2128
2129                                 // Is the member of the correct type ?
2130                                 if ((entry.EntryType & type & EntryType.MaskType) == 0)
2131                                         continue;
2132
2133                                 // Is the member static/non-static ?
2134                                 if ((entry.EntryType & type & EntryType.MaskStatic) == 0)
2135                                         continue;
2136
2137                                 // Apply the filter to it.
2138                                 if (filter (entry.Member, criteria)) {
2139                                         if ((entry.EntryType & EntryType.MaskType) != EntryType.Method)
2140                                                 do_method_search = false;
2141                                         global.Add (entry.Member);
2142                                 }
2143                         }
2144
2145                         Timer.StopTimer (TimerType.CachedLookup);
2146
2147                         // If we have a method cache and we aren't already doing a method-only
2148                         // search, we restart in method-only search mode if the first match is
2149                         // a method.  This ensures that we return a MemberInfo with the correct
2150                         // ReflectedType for inherited methods.
2151                         if (do_method_search && (global.Count > 0)){
2152                                 using_global = false;
2153
2154                                 return FindMembers (MemberTypes.Method, bf, name, filter, criteria);
2155                         }
2156
2157                         using_global = false;
2158                         MemberInfo [] copy = new MemberInfo [global.Count];
2159                         global.CopyTo (copy);
2160                         return copy;
2161                 }
2162                 
2163                 //
2164                 // This finds the method or property for us to override. invocationType is the type where
2165                 // the override is going to be declared, name is the name of the method/property, and
2166                 // paramTypes is the parameters, if any to the method or property
2167                 //
2168                 // Because the MemberCache holds members from this class and all the base classes,
2169                 // we can avoid tons of reflection stuff.
2170                 //
2171                 public MemberInfo FindMemberToOverride (Type invocationType, string name, Type [] paramTypes, bool is_property)
2172                 {
2173                         ArrayList applicable;
2174                         if (method_hash != null && !is_property)
2175                                 applicable = (ArrayList) method_hash [name];
2176                         else
2177                                 applicable = (ArrayList) member_hash [name];
2178                         
2179                         if (applicable == null)
2180                                 return null;
2181                         //
2182                         // Walk the chain of methods, starting from the top.
2183                         //
2184                         for (int i = applicable.Count - 1; i >= 0; i--) {
2185                                 CacheEntry entry = (CacheEntry) applicable [i];
2186                                 
2187                                 if ((entry.EntryType & (is_property ? (EntryType.Property | EntryType.Field) : EntryType.Method)) == 0)
2188                                         continue;
2189
2190                                 PropertyInfo pi = null;
2191                                 MethodInfo mi = null;
2192                                 FieldInfo fi = null;
2193                                 Type [] cmpAttrs = null;
2194                                 
2195                                 if (is_property) {
2196                                         if ((entry.EntryType & EntryType.Field) != 0) {
2197                                                 fi = (FieldInfo)entry.Member;
2198
2199                                                 // TODO: For this case we ignore member type
2200                                                 //fb = TypeManager.GetField (fi);
2201                                                 //cmpAttrs = new Type[] { fb.MemberType };
2202                                         } else {
2203                                                 pi = (PropertyInfo) entry.Member;
2204                                                 cmpAttrs = TypeManager.GetArgumentTypes (pi);
2205                                         }
2206                                 } else {
2207                                         mi = (MethodInfo) entry.Member;
2208                                         cmpAttrs = TypeManager.GetArgumentTypes (mi);
2209                                 }
2210
2211                                 if (fi != null) {
2212                                         // TODO: Almost duplicate !
2213                                         // Check visibility
2214                                         switch (fi.Attributes & FieldAttributes.FieldAccessMask) {
2215                                                 case FieldAttributes.Private:
2216                                                         //
2217                                                         // A private method is Ok if we are a nested subtype.
2218                                                         // The spec actually is not very clear about this, see bug 52458.
2219                                                         //
2220                                                         if (invocationType != entry.Container.Type &
2221                                                                 TypeManager.IsNestedChildOf (invocationType, entry.Container.Type))
2222                                                                 continue;
2223
2224                                                         break;
2225                                                 case FieldAttributes.FamANDAssem:
2226                                                 case FieldAttributes.Assembly:
2227                                                         //
2228                                                         // Check for assembly methods
2229                                                         //
2230                                                         if (mi.DeclaringType.Assembly != CodeGen.Assembly.Builder)
2231                                                                 continue;
2232                                                         break;
2233                                         }
2234                                         return entry.Member;
2235                                 }
2236
2237                                 //
2238                                 // Check the arguments
2239                                 //
2240                                 if (cmpAttrs.Length != paramTypes.Length)
2241                                         continue;
2242
2243                                 for (int j = cmpAttrs.Length - 1; j >= 0; j --) {
2244                                         if (!paramTypes [j].Equals (cmpAttrs [j]))
2245                                                 goto next;
2246                                 }
2247                                 
2248                                 //
2249                                 // get one of the methods because this has the visibility info.
2250                                 //
2251                                 if (is_property) {
2252                                         mi = pi.GetGetMethod (true);
2253                                         if (mi == null)
2254                                                 mi = pi.GetSetMethod (true);
2255                                 }
2256                                 
2257                                 //
2258                                 // Check visibility
2259                                 //
2260                                 switch (mi.Attributes & MethodAttributes.MemberAccessMask) {
2261                                 case MethodAttributes.Private:
2262                                         //
2263                                         // A private method is Ok if we are a nested subtype.
2264                                         // The spec actually is not very clear about this, see bug 52458.
2265                                         //
2266                                         if (invocationType == entry.Container.Type ||
2267                                             TypeManager.IsNestedChildOf (invocationType, entry.Container.Type))
2268                                                 return entry.Member;
2269                                         
2270                                         break;
2271                                 case MethodAttributes.FamANDAssem:
2272                                 case MethodAttributes.Assembly:
2273                                         //
2274                                         // Check for assembly methods
2275                                         //
2276                                         if (mi.DeclaringType.Assembly == CodeGen.Assembly.Builder)
2277                                                 return entry.Member;
2278                                         
2279                                         break;
2280                                 default:
2281                                         //
2282                                         // A protected method is ok, because we are overriding.
2283                                         // public is always ok.
2284                                         //
2285                                         return entry.Member;
2286                                 }
2287                         next:
2288                                 ;
2289                         }
2290                         
2291                         return null;
2292                 }
2293
2294                 /// <summary>
2295                 /// The method is looking for conflict with inherited symbols (errors CS0108, CS0109).
2296                 /// We handle two cases. The first is for types without parameters (events, field, properties).
2297                 /// The second are methods, indexers and this is why ignore_complex_types is here.
2298                 /// The latest param is temporary hack. See DoDefineMembers method for more info.
2299                 /// </summary>
2300                 public MemberInfo FindMemberWithSameName (string name, bool ignore_complex_types, MemberInfo ignore_member)
2301                 {
2302                         ArrayList applicable = null;
2303  
2304                         if (method_hash != null)
2305                                 applicable = (ArrayList) method_hash [name];
2306  
2307                         if (applicable != null) {
2308                                 for (int i = applicable.Count - 1; i >= 0; i--) {
2309                                         CacheEntry entry = (CacheEntry) applicable [i];
2310                                         if ((entry.EntryType & EntryType.Public) != 0)
2311                                                 return entry.Member;
2312                                 }
2313                         }
2314  
2315                         if (member_hash == null)
2316                                 return null;
2317                         applicable = (ArrayList) member_hash [name];
2318                         
2319                         if (applicable != null) {
2320                                 for (int i = applicable.Count - 1; i >= 0; i--) {
2321                                         CacheEntry entry = (CacheEntry) applicable [i];
2322                                         if ((entry.EntryType & EntryType.Public) != 0 & entry.Member != ignore_member) {
2323                                                 if (ignore_complex_types) {
2324                                                         if ((entry.EntryType & EntryType.Method) != 0)
2325                                                                 continue;
2326  
2327                                                         // Does exist easier way how to detect indexer ?
2328                                                         if ((entry.EntryType & EntryType.Property) != 0) {
2329                                                                 Type[] arg_types = TypeManager.GetArgumentTypes ((PropertyInfo)entry.Member);
2330                                                                 if (arg_types.Length == 1)
2331                                                                         continue;
2332                                                         }
2333                                                 }
2334                                                 return entry.Member;
2335                                         }
2336                                 }
2337                         }
2338                         return null;
2339                 }
2340
2341                 Hashtable locase_table;
2342  
2343                 /// <summary>
2344                 /// Builds low-case table for CLS Compliance test
2345                 /// </summary>
2346                 public Hashtable GetPublicMembers ()
2347                 {
2348                         if (locase_table != null)
2349                                 return locase_table;
2350  
2351                         locase_table = new Hashtable ();
2352                         foreach (DictionaryEntry entry in member_hash) {
2353                                 ArrayList members = (ArrayList)entry.Value;
2354                                 for (int ii = 0; ii < members.Count; ++ii) {
2355                                         CacheEntry member_entry = (CacheEntry) members [ii];
2356  
2357                                         if ((member_entry.EntryType & EntryType.Public) == 0)
2358                                                 continue;
2359  
2360                                         // TODO: Does anyone know easier way how to detect that member is internal ?
2361                                         switch (member_entry.EntryType & EntryType.MaskType) {
2362                                                 case EntryType.Constructor:
2363                                                         continue;
2364  
2365                                                 case EntryType.Field:
2366                                                         if ((((FieldInfo)member_entry.Member).Attributes & (FieldAttributes.Assembly | FieldAttributes.Public)) == FieldAttributes.Assembly)
2367                                                                 continue;
2368                                                         break;
2369  
2370                                                 case EntryType.Method:
2371                                                         if ((((MethodInfo)member_entry.Member).Attributes & (MethodAttributes.Assembly | MethodAttributes.Public)) == MethodAttributes.Assembly)
2372                                                                 continue;
2373                                                         break;
2374  
2375                                                 case EntryType.Property:
2376                                                         PropertyInfo pi = (PropertyInfo)member_entry.Member;
2377                                                         if (pi.GetSetMethod () == null && pi.GetGetMethod () == null)
2378                                                                 continue;
2379                                                         break;
2380  
2381                                                 case EntryType.Event:
2382                                                         EventInfo ei = (EventInfo)member_entry.Member;
2383                                                         MethodInfo mi = ei.GetAddMethod ();
2384                                                         if ((mi.Attributes & (MethodAttributes.Assembly | MethodAttributes.Public)) == MethodAttributes.Assembly)
2385                                                                 continue;
2386                                                         break;
2387                                         }
2388                                         string lcase = ((string)entry.Key).ToLower (System.Globalization.CultureInfo.InvariantCulture);
2389                                         locase_table [lcase] = member_entry.Member;
2390                                         break;
2391                                 }
2392                         }
2393                         return locase_table;
2394                 }
2395  
2396                 public Hashtable Members {
2397                         get {
2398                                 return member_hash;
2399                         }
2400                 }
2401  
2402                 /// <summary>
2403                 /// Cls compliance check whether methods or constructors parameters differing only in ref or out, or in array rank
2404                 /// </summary>
2405                 public void VerifyClsParameterConflict (ArrayList al, MethodCore method, MemberInfo this_builder)
2406                 {
2407                         EntryType tested_type = (method is Constructor ? EntryType.Constructor : EntryType.Method) | EntryType.Public;
2408  
2409                         for (int i = 0; i < al.Count; ++i) {
2410                                 MemberCache.CacheEntry entry = (MemberCache.CacheEntry) al [i];
2411                 
2412                                 // skip itself
2413                                 if (entry.Member == this_builder)
2414                                         continue;
2415                 
2416                                 if ((entry.EntryType & tested_type) != tested_type)
2417                                         continue;
2418                 
2419                                 MethodBase method_to_compare = (MethodBase)entry.Member;
2420                                 if (AttributeTester.AreOverloadedMethodParamsClsCompliant (method.ParameterTypes, TypeManager.GetArgumentTypes (method_to_compare)))
2421                                         continue;
2422
2423                                 IMethodData md = TypeManager.GetMethod (method_to_compare);
2424
2425                                 // TODO: now we are ignoring CLSCompliance(false) on method from other assembly which is buggy.
2426                                 // However it is exactly what csc does.
2427                                 if (md != null && !md.IsClsCompliaceRequired (method.Parent))
2428                                         continue;
2429                 
2430                                 Report.SymbolRelatedToPreviousError (entry.Member);
2431                                 Report.Error (3006, method.Location, "Overloaded method '{0}' differing only in ref or out, or in array rank, is not CLS-compliant", method.GetSignatureForError ());
2432                         }
2433                 }
2434         }
2435 }