2002-11-14 Martin Baulig <martin@ximian.com>
[mono.git] / mcs / mcs / typemanager.cs
1 //
2 // typemanager.cs: C# type manager
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //         Ravi Pratap     (ravi@ximian.com)
6 //
7 // Licensed under the terms of the GNU GPL
8 //
9 // (C) 2001 Ximian, Inc (http://www.ximian.com)
10 //
11 //
12
13 //
14 // We will eventually remove the SIMPLE_SPEEDUP, and should never change 
15 // the behavior of the compilation.  This can be removed if we rework
16 // the code to get a list of namespaces available.
17 //
18 #define SIMPLE_SPEEDUP
19
20 using System;
21 using System.Globalization;
22 using System.Collections;
23 using System.Reflection;
24 using System.Reflection.Emit;
25 using System.Text.RegularExpressions;
26 using System.Runtime.CompilerServices;
27 using System.Diagnostics;
28
29 namespace Mono.CSharp {
30
31 public class TypeManager {
32         //
33         // A list of core types that the compiler requires or uses
34         //
35         static public Type object_type;
36         static public Type value_type;
37         static public Type string_type;
38         static public Type int32_type;
39         static public Type uint32_type;
40         static public Type int64_type;
41         static public Type uint64_type;
42         static public Type float_type;
43         static public Type double_type;
44         static public Type char_type;
45         static public Type char_ptr_type;
46         static public Type short_type;
47         static public Type decimal_type;
48         static public Type bool_type;
49         static public Type sbyte_type;
50         static public Type byte_type;
51         static public Type ushort_type;
52         static public Type enum_type;
53         static public Type delegate_type;
54         static public Type multicast_delegate_type;
55         static public Type void_type;
56         static public Type enumeration_type;
57         static public Type array_type;
58         static public Type runtime_handle_type;
59         static public Type icloneable_type;
60         static public Type type_type;
61         static public Type ienumerator_type;
62         static public Type idisposable_type;
63         static public Type default_member_type;
64         static public Type iasyncresult_type;
65         static public Type asynccallback_type;
66         static public Type intptr_type;
67         static public Type monitor_type;
68         static public Type runtime_field_handle_type;
69         static public Type attribute_type;
70         static public Type attribute_usage_type;
71         static public Type dllimport_type;
72         static public Type unverifiable_code_type;
73         static public Type methodimpl_attr_type;
74         static public Type marshal_as_attr_type;
75         static public Type param_array_type;
76         static public Type void_ptr_type;
77         static public Type indexer_name_type;
78         static public Type exception_type;
79         static public object obsolete_attribute_type;
80         static public object conditional_attribute_type;
81
82         //
83         // An empty array of types
84         //
85         static public Type [] NoTypes;
86
87
88         // 
89         // Expressions representing the internal types.  Used during declaration
90         // definition.
91         //
92         static public Expression system_object_expr, system_string_expr; 
93         static public Expression system_boolean_expr, system_decimal_expr;
94         static public Expression system_single_expr, system_double_expr;
95         static public Expression system_sbyte_expr, system_byte_expr;
96         static public Expression system_int16_expr, system_uint16_expr;
97         static public Expression system_int32_expr, system_uint32_expr;
98         static public Expression system_int64_expr, system_uint64_expr;
99         static public Expression system_char_expr, system_void_expr;
100         static public Expression system_asynccallback_expr;
101         static public Expression system_iasyncresult_expr;
102
103         //
104         // This is only used when compiling corlib
105         //
106         static public Type system_int32_type;
107         static public Type system_array_type;
108         static public Type system_type_type;
109         static public Type system_assemblybuilder_type;
110         static public MethodInfo system_int_array_get_length;
111         static public MethodInfo system_int_array_get_rank;
112         static public MethodInfo system_object_array_clone;
113         static public MethodInfo system_int_array_get_length_int;
114         static public MethodInfo system_int_array_get_lower_bound_int;
115         static public MethodInfo system_int_array_get_upper_bound_int;
116         static public MethodInfo system_void_array_copyto_array_int;
117         static public MethodInfo system_void_set_corlib_type_builders;
118
119         
120         //
121         // Internal, not really used outside
122         //
123         static Type runtime_helpers_type;
124         
125         //
126         // These methods are called by code generated by the compiler
127         //
128         static public MethodInfo string_concat_string_string;
129         static public MethodInfo string_concat_object_object;
130         static public MethodInfo string_isinterneted_string;
131         static public MethodInfo system_type_get_type_from_handle;
132         static public MethodInfo object_getcurrent_void;
133         static public MethodInfo bool_movenext_void;
134         static public MethodInfo void_dispose_void;
135         static public MethodInfo void_monitor_enter_object;
136         static public MethodInfo void_monitor_exit_object;
137         static public MethodInfo void_initializearray_array_fieldhandle;
138         static public MethodInfo int_getlength_int;
139         static public MethodInfo delegate_combine_delegate_delegate;
140         static public MethodInfo delegate_remove_delegate_delegate;
141         static public MethodInfo int_get_offset_to_string_data;
142         static public MethodInfo int_array_get_length;
143         static public MethodInfo int_array_get_rank;
144         static public MethodInfo object_array_clone;
145         static public MethodInfo int_array_get_length_int;
146         static public MethodInfo int_array_get_lower_bound_int;
147         static public MethodInfo int_array_get_upper_bound_int;
148         static public MethodInfo void_array_copyto_array_int;
149         
150         //
151         // The attribute constructors.
152         //
153         static public ConstructorInfo cons_param_array_attribute;
154         static public ConstructorInfo void_decimal_ctor_five_args;
155         static public ConstructorInfo unverifiable_code_ctor;
156         
157         // <remarks>
158         //   Holds the Array of Assemblies that have been loaded
159         //   (either because it is the default or the user used the
160         //   -r command line option)
161         // </remarks>
162         static Assembly [] assemblies;
163
164         // <remarks>
165         //  Keeps a list of module builders. We used this to do lookups
166         //  on the modulebuilder using GetType -- needed for arrays
167         // </remarks>
168         static ModuleBuilder [] modules;
169
170         // <remarks>
171         //   This is the type_cache from the assemblies to avoid
172         //   hitting System.Reflection on every lookup.
173         // </summary>
174         static Hashtable types;
175
176         // <remarks>
177         //  This is used to hotld the corresponding TypeContainer objects
178         //  since we need this in FindMembers
179         // </remarks>
180         static Hashtable typecontainers;
181
182         // <remarks>
183         //   Keeps track of those types that are defined by the
184         //   user's program
185         // </remarks>
186         static ArrayList user_types;
187
188         static PtrHashtable builder_to_declspace;
189
190         // <remarks>
191         //   Tracks the interfaces implemented by typebuilders.  We only
192         //   enter those who do implement or or more interfaces
193         // </remarks>
194         static PtrHashtable builder_to_ifaces;
195
196         // <remarks>
197         //   Maps MethodBase.RuntimeTypeHandle to a Type array that contains
198         //   the arguments to the method
199         // </remarks>
200         static Hashtable method_arguments;
201
202         // <remarks>
203         //   Maps PropertyBuilder to a Type array that contains
204         //   the arguments to the indexer
205         // </remarks>
206         static Hashtable indexer_arguments;
207
208         // <remarks>
209         //   Maybe `method_arguments' should be replaced and only
210         //   method_internal_params should be kept?
211         // <remarks>
212         static Hashtable method_internal_params;
213
214         // <remarks>
215         //  Keeps track of attribute types
216         // </remarks>
217
218         static Hashtable builder_to_attr;
219
220         // <remarks>
221         //  Keeps track of methods
222         // </remarks>
223
224         static Hashtable builder_to_method;
225
226         struct Signature {
227                 public string name;
228                 public Type [] args;
229         }
230
231         /// <summary>
232         ///   A filter for Findmembers that uses the Signature object to
233         ///   extract objects
234         /// </summary>
235         static bool SignatureFilter (MemberInfo mi, object criteria)
236         {
237                 Signature sig = (Signature) criteria;
238
239                 if (!(mi is MethodBase))
240                         return false;
241                 
242                 if (mi.Name != sig.name)
243                         return false;
244
245                 int count = sig.args.Length;
246                 
247                 if (mi is MethodBuilder || mi is ConstructorBuilder){
248                         Type [] candidate_args = GetArgumentTypes ((MethodBase) mi);
249
250                         if (candidate_args.Length != count)
251                                 return false;
252                         
253                         for (int i = 0; i < count; i++)
254                                 if (candidate_args [i] != sig.args [i])
255                                         return false;
256                         
257                         return true;
258                 } else {
259                         ParameterInfo [] pars = ((MethodBase) mi).GetParameters ();
260
261                         if (pars.Length != count)
262                                 return false;
263
264                         for (int i = 0; i < count; i++)
265                                 if (pars [i].ParameterType != sig.args [i])
266                                         return false;
267                         return true;
268                 }
269         }
270
271         // A delegate that points to the filter above.
272         static MemberFilter signature_filter;
273
274         //
275         // These are expressions that represent some of the internal data types, used
276         // elsewhere
277         //
278         static void InitExpressionTypes ()
279         {
280                 system_object_expr  = new TypeLookupExpression ("System.Object");
281                 system_string_expr  = new TypeLookupExpression ("System.String");
282                 system_boolean_expr = new TypeLookupExpression ("System.Boolean");
283                 system_decimal_expr = new TypeLookupExpression ("System.Decimal");
284                 system_single_expr  = new TypeLookupExpression ("System.Single");
285                 system_double_expr  = new TypeLookupExpression ("System.Double");
286                 system_sbyte_expr   = new TypeLookupExpression ("System.SByte");
287                 system_byte_expr    = new TypeLookupExpression ("System.Byte");
288                 system_int16_expr   = new TypeLookupExpression ("System.Int16");
289                 system_uint16_expr  = new TypeLookupExpression ("System.UInt16");
290                 system_int32_expr   = new TypeLookupExpression ("System.Int32");
291                 system_uint32_expr  = new TypeLookupExpression ("System.UInt32");
292                 system_int64_expr   = new TypeLookupExpression ("System.Int64");
293                 system_uint64_expr  = new TypeLookupExpression ("System.UInt64");
294                 system_char_expr    = new TypeLookupExpression ("System.Char");
295                 system_void_expr    = new TypeLookupExpression ("System.Void");
296                 system_asynccallback_expr = new TypeLookupExpression ("System.AsyncCallback");
297                 system_iasyncresult_expr = new TypeLookupExpression ("System.IAsyncResult");
298         }
299         
300         static TypeManager ()
301         {
302                 assemblies = new Assembly [0];
303                 modules = null;
304                 user_types = new ArrayList ();
305                 
306                 types = new Hashtable ();
307                 typecontainers = new Hashtable ();
308                 
309                 builder_to_declspace = new PtrHashtable ();
310                 builder_to_attr = new PtrHashtable ();
311                 builder_to_method = new PtrHashtable ();
312                 method_arguments = new PtrHashtable ();
313                 method_internal_params = new PtrHashtable ();
314                 indexer_arguments = new PtrHashtable ();
315                 builder_to_ifaces = new PtrHashtable ();
316                 
317                 NoTypes = new Type [0];
318
319                 signature_filter = new MemberFilter (SignatureFilter);
320                 InitExpressionTypes ();
321         }
322
323         public static void AddUserType (string name, TypeBuilder t, Type [] ifaces)
324         {
325                 try {
326                         types.Add (name, t);
327                 } catch {
328                         Type prev = (Type) types [name];
329                         TypeContainer tc = builder_to_declspace [prev] as TypeContainer;
330
331                         if (tc != null){
332                                 //
333                                 // This probably never happens, as we catch this before
334                                 //
335                                 Report.Error (-17, "The type `" + name + "' has already been defined.");
336                                 return;
337                         }
338
339                         tc = builder_to_declspace [t] as TypeContainer;
340                         
341                         Report.Warning (
342                                 1595, "The type `" + name + "' is defined in an existing assembly;"+
343                                 " Using the new definition from: " + tc.Location);
344                         Report.Warning (1595, "Previously defined in: " + prev.Assembly.FullName);
345                         
346                         types.Remove (name);
347                         types.Add (name, t);
348                 }
349                 user_types.Add (t);
350                         
351                 if (ifaces != null)
352                         builder_to_ifaces [t] = ifaces;
353         }
354
355         //
356         // This entry point is used by types that we define under the covers
357         // 
358         public static void RegisterBuilder (TypeBuilder tb, Type [] ifaces)
359         {
360                 if (ifaces != null)
361                         builder_to_ifaces [tb] = ifaces;
362         }
363         
364         public static void AddUserType (string name, TypeBuilder t, TypeContainer tc, Type [] ifaces)
365         {
366                 builder_to_declspace.Add (t, tc);
367                 typecontainers.Add (name, tc);
368                 AddUserType (name, t, ifaces);
369         }
370
371         public static void AddDelegateType (string name, TypeBuilder t, Delegate del)
372         {
373                 types.Add (name, t);
374                 builder_to_declspace.Add (t, del);
375         }
376         
377         public static void AddEnumType (string name, TypeBuilder t, Enum en)
378         {
379                 types.Add (name, t);
380                 builder_to_declspace.Add (t, en);
381         }
382
383         public static void AddUserInterface (string name, TypeBuilder t, Interface i, Type [] ifaces)
384         {
385                 AddUserType (name, t, ifaces);
386                 builder_to_declspace.Add (t, i);
387         }
388
389         public static void AddMethod (MethodBuilder builder, MethodData method)
390         {
391                 builder_to_method.Add (builder, method);
392         }
393
394         public static void RegisterAttrType (Type t, TypeContainer tc)
395         {
396                 builder_to_attr.Add (t, tc);
397         }
398
399         /// <summary>
400         ///   Returns the TypeContainer whose Type is `t' or null if there is no
401         ///   TypeContainer for `t' (ie, the Type comes from a library)
402         /// </summary>
403         public static TypeContainer LookupTypeContainer (Type t)
404         {
405                 return builder_to_declspace [t] as TypeContainer;
406         }
407
408         public static IMemberContainer LookupMemberContainer (Type t)
409         {
410                 if (t is TypeBuilder) {
411                         IMemberContainer container = builder_to_declspace [t] as IMemberContainer;
412                         if (container != null)
413                                 return container;
414                 }
415
416                 return TypeHandle.GetTypeHandle (t);
417         }
418
419         public static Interface LookupInterface (Type t)
420         {
421                 return builder_to_declspace [t] as Interface;
422         }
423
424         public static Delegate LookupDelegate (Type t)
425         {
426                 return builder_to_declspace [t] as Delegate;
427         }
428
429         public static Enum LookupEnum (Type t)
430         {
431                 return builder_to_declspace [t] as Enum;
432         }
433         
434         public static TypeContainer LookupAttr (Type t)
435         {
436                 return (TypeContainer) builder_to_attr [t];
437         }
438         
439         /// <summary>
440         ///   Registers an assembly to load types from.
441         /// </summary>
442         public static void AddAssembly (Assembly a)
443         {
444                 int top = assemblies.Length;
445                 Assembly [] n = new Assembly [top + 1];
446
447                 assemblies.CopyTo (n, 0);
448                 
449                 n [top] = a;
450                 assemblies = n;
451         }
452
453         /// <summary>
454         ///  Registers a module builder to lookup types from
455         /// </summary>
456         public static void AddModule (ModuleBuilder mb)
457         {
458                 int top = modules != null ? modules.Length : 0;
459                 ModuleBuilder [] n = new ModuleBuilder [top + 1];
460
461                 if (modules != null)
462                         modules.CopyTo (n, 0);
463                 n [top] = mb;
464                 modules = n;
465         }
466
467         //
468         // Low-level lookup, cache-less
469         //
470         static Type LookupTypeReflection (string name)
471         {
472                 Type t;
473
474                 foreach (Assembly a in assemblies){
475                         t = a.GetType (name);
476                         if (t != null)
477                                 return t;
478                 }
479
480                 foreach (ModuleBuilder mb in modules) {
481                         t = mb.GetType (name);
482                         if (t != null){
483                                 return t;
484                         }
485                 }
486                 return null;
487         }
488
489         static Hashtable negative_hits = new Hashtable ();
490         
491         //
492         // This function is used when you want to avoid the lookups, and want to go
493         // directly to the source.  This will use the cache.
494         //
495         // Notice that bypassing the cache is bad, because on Microsoft.NET runtime
496         // GetType ("DynamicType[]") != GetType ("DynamicType[]"), and there is no
497         // way to test things other than doing a fullname compare
498         //
499         public static Type LookupTypeDirect (string name)
500         {
501                 Type t = (Type) types [name];
502                 if (t != null)
503                         return t;
504
505                 t = LookupTypeReflection (name);
506                 if (t == null)
507                         return null;
508
509                 types [name] = t;
510                 return t;
511         }
512         
513         /// <summary>
514         ///   Returns the Type associated with @name, takes care of the fact that
515         ///   reflection expects nested types to be separated from the main type
516         ///   with a "+" instead of a "."
517         /// </summary>
518         public static Type LookupType (string name)
519         {
520                 Type t;
521
522                 //
523                 // First lookup in user defined and cached values
524                 //
525
526                 t = (Type) types [name];
527                 if (t != null)
528                         return t;
529
530 #if SIMPLE_SPEEDUP
531                 if (negative_hits.Contains (name))
532                         return null;
533 #endif
534                 
535                 //
536                 // Optimization: ComposedCast will work with an existing type, and might already have the
537                 // full name of the type, so the full system lookup can probably be avoided.
538                 //
539                 
540                 string [] elements = name.Split ('.');
541                 int count = elements.Length;
542
543                 for (int n = 1; n <= count; n++){
544                         string top_level_type = String.Join (".", elements, 0, n);
545
546                         t = (Type) types [top_level_type];
547                         if (t == null){
548                                 t = LookupTypeReflection (top_level_type);
549                                 if (t == null)
550                                         continue;
551                         }
552                         
553                         if (count == n){
554                                 types [name] = t;
555                                 return t;
556                         } 
557
558                         //
559                         // We know that System.Object does not have children, and since its the parent of 
560                         // all the objects, it always gets probbed for inner classes. 
561                         //
562                         if (top_level_type == "System.Object")
563                                 return null;
564                         
565                         string newt = top_level_type + "+" + String.Join ("+", elements, n, count - n);
566                         t = LookupTypeDirect (newt);
567                         if (t != null)
568                                 types [newt] = t;
569                         return t;
570                 }
571
572 #if SIMPLE_SPEEDUP
573                 negative_hits [name] = true;
574 #endif
575                 return null;
576         }
577
578         //
579         // Returns a list of all namespaces in the assemblies and types loaded.
580         //
581         public static Hashtable GetNamespaces ()
582         {
583                 Hashtable namespaces = new Hashtable ();
584
585                 foreach (Assembly a in assemblies){
586                         foreach (Type t in a.GetTypes ()){
587                                 string ns = t.Namespace;
588
589                                 if (namespaces.Contains (ns))
590                                         continue;
591                                 namespaces [ns] = ns;
592                         }
593                 }
594
595                 foreach (ModuleBuilder mb in modules){
596                         foreach (Type t in mb.GetTypes ()){
597                                 string ns = t.Namespace;
598
599                                 if (namespaces.Contains (ns))
600                                         continue;
601                                 namespaces [ns] = ns;
602                         }
603                 }
604                 Console.WriteLine ("Namespaces: " + namespaces.Count);
605                 return namespaces;
606         }
607
608         public static void GetAllTypes ()
609         {
610                 Hashtable namespaces = new Hashtable ();
611
612                 foreach (Assembly a in assemblies){
613                         foreach (Type t in a.GetTypes ()){
614                         }
615                 }
616
617                 foreach (ModuleBuilder mb in modules){
618                         foreach (Type t in mb.GetTypes ()){
619                         }
620                 }
621         }
622         
623         /// <summary>
624         ///   Returns the C# name of a type if possible, or the full type name otherwise
625         /// </summary>
626         static public string CSharpName (Type t)
627         {
628                 return Regex.Replace (t.FullName, 
629                         @"^System\." +
630                         @"(Int32|UInt32|Int16|Uint16|Int64|UInt64|" +
631                         @"Single|Double|Char|Decimal|Byte|SByte|Object|" +
632                         @"Boolean|String|Void)" +
633                         @"(\W+|\b)", 
634                         new MatchEvaluator (CSharpNameMatch));
635         }       
636         
637         static String CSharpNameMatch (Match match) 
638         {
639                 string s = match.Groups [1].Captures [0].Value;
640                 return s.ToLower ().
641                 Replace ("int32", "int").
642                 Replace ("uint32", "uint").
643                 Replace ("int16", "short").
644                 Replace ("uint16", "ushort").
645                 Replace ("int64", "long").
646                 Replace ("uint64", "ulong").
647                 Replace ("single", "float").
648                 Replace ("boolean", "bool")
649                 + match.Groups [2].Captures [0].Value;
650         }
651
652         /// <summary>
653         ///   Returns the signature of the method
654         /// </summary>
655         static public string CSharpSignature (MethodBase mb)
656         {
657                 string sig = "(";
658
659                 //
660                 // FIXME: We should really have a single function to do
661                 // everything instead of the following 5 line pattern
662                 //
663                 ParameterData iparams = LookupParametersByBuilder (mb);
664
665                 if (iparams == null){
666                         ParameterInfo [] pi = mb.GetParameters ();
667                         iparams = new ReflectionParameters (pi);
668                 }
669                 
670                 for (int i = 0; i < iparams.Count; i++) {
671                         if (i > 0) {
672                                 sig += ", ";
673                         }
674                         sig += iparams.ParameterDesc(i);
675                 }
676                 sig += ")";
677
678                 return mb.DeclaringType.Name + "." + mb.Name + sig;
679         }
680
681         /// <summary>
682         ///   Looks up a type, and aborts if it is not found.  This is used
683         ///   by types required by the compiler
684         /// </summary>
685         static Type CoreLookupType (string name)
686         {
687                 Type t = LookupType (name);
688
689                 if (t == null){
690                         Report.Error (518, "The predefined type `" + name + "' is not defined or imported");
691                         Environment.Exit (0);
692                 }
693
694                 return t;
695         }
696
697         /// <summary>
698         ///   Returns the MethodInfo for a method named `name' defined
699         ///   in type `t' which takes arguments of types `args'
700         /// </summary>
701         static MethodInfo GetMethod (Type t, string name, Type [] args)
702         {
703                 MemberList list;
704                 Signature sig;
705
706                 sig.name = name;
707                 sig.args = args;
708                 
709                 list = FindMembers (t, MemberTypes.Method, instance_and_static | BindingFlags.Public,
710                                     signature_filter, sig);
711                 if (list.Count == 0) {
712                         Report.Error (-19, "Can not find the core function `" + name + "'");
713                         return null;
714                 }
715
716                 MethodInfo mi = list [0] as MethodInfo;
717                 if (mi == null) {
718                         Report.Error (-19, "Can not find the core function `" + name + "'");
719                         return null;
720                 }
721
722                 return mi;
723         }
724
725         /// <summary>
726         ///    Returns the ConstructorInfo for "args"
727         /// </summary>
728         static ConstructorInfo GetConstructor (Type t, Type [] args)
729         {
730                 MemberList list;
731                 Signature sig;
732
733                 sig.name = ".ctor";
734                 sig.args = args;
735                 
736                 list = FindMembers (t, MemberTypes.Constructor,
737                                     instance_and_static | BindingFlags.Public | BindingFlags.DeclaredOnly,
738                                     signature_filter, sig);
739                 if (list.Count == 0){
740                         Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
741                         return null;
742                 }
743
744                 ConstructorInfo ci = list [0] as ConstructorInfo;
745                 if (ci == null){
746                         Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
747                         return null;
748                 }
749
750                 return ci;
751         }
752
753         public static void InitEnumUnderlyingTypes ()
754         {
755
756                 int32_type    = CoreLookupType ("System.Int32");
757                 int64_type    = CoreLookupType ("System.Int64");
758                 uint32_type   = CoreLookupType ("System.UInt32"); 
759                 uint64_type   = CoreLookupType ("System.UInt64"); 
760                 byte_type     = CoreLookupType ("System.Byte");
761                 sbyte_type    = CoreLookupType ("System.SByte");
762                 short_type    = CoreLookupType ("System.Int16");
763                 ushort_type   = CoreLookupType ("System.UInt16");
764         }
765         
766         /// <remarks>
767         ///   The types have to be initialized after the initial
768         ///   population of the type has happened (for example, to
769         ///   bootstrap the corlib.dll
770         /// </remarks>
771         public static void InitCoreTypes ()
772         {
773                 object_type   = CoreLookupType ("System.Object");
774                 value_type    = CoreLookupType ("System.ValueType");
775
776                 InitEnumUnderlyingTypes ();
777
778                 char_type     = CoreLookupType ("System.Char");
779                 string_type   = CoreLookupType ("System.String");
780                 float_type    = CoreLookupType ("System.Single");
781                 double_type   = CoreLookupType ("System.Double");
782                 char_ptr_type = CoreLookupType ("System.Char*");
783                 decimal_type  = CoreLookupType ("System.Decimal");
784                 bool_type     = CoreLookupType ("System.Boolean");
785                 enum_type     = CoreLookupType ("System.Enum");
786
787                 multicast_delegate_type = CoreLookupType ("System.MulticastDelegate");
788                 delegate_type           = CoreLookupType ("System.Delegate");
789
790                 array_type    = CoreLookupType ("System.Array");
791                 void_type     = CoreLookupType ("System.Void");
792                 type_type     = CoreLookupType ("System.Type");
793
794                 runtime_field_handle_type = CoreLookupType ("System.RuntimeFieldHandle");
795                 runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices.RuntimeHelpers");
796                 default_member_type  = CoreLookupType ("System.Reflection.DefaultMemberAttribute");
797                 runtime_handle_type  = CoreLookupType ("System.RuntimeTypeHandle");
798                 asynccallback_type   = CoreLookupType ("System.AsyncCallback");
799                 iasyncresult_type    = CoreLookupType ("System.IAsyncResult");
800                 ienumerator_type     = CoreLookupType ("System.Collections.IEnumerator");
801                 idisposable_type     = CoreLookupType ("System.IDisposable");
802                 icloneable_type      = CoreLookupType ("System.ICloneable");
803                 monitor_type         = CoreLookupType ("System.Threading.Monitor");
804                 intptr_type          = CoreLookupType ("System.IntPtr");
805
806                 attribute_type       = CoreLookupType ("System.Attribute");
807                 attribute_usage_type = CoreLookupType ("System.AttributeUsageAttribute");
808                 dllimport_type       = CoreLookupType ("System.Runtime.InteropServices.DllImportAttribute");
809                 methodimpl_attr_type = CoreLookupType ("System.Runtime.CompilerServices.MethodImplAttribute");
810                 marshal_as_attr_type  = CoreLookupType ("System.Runtime.InteropServices.MarshalAsAttribute");
811                 param_array_type      = CoreLookupType ("System.ParamArrayAttribute");
812
813                 unverifiable_code_type= CoreLookupType ("System.Security.UnverifiableCodeAttribute");
814
815                 void_ptr_type         = CoreLookupType ("System.Void*");
816
817                 indexer_name_type     = CoreLookupType ("System.Runtime.CompilerServices.IndexerNameAttribute");
818
819                 exception_type        = CoreLookupType ("System.Exception");
820
821                 //
822                 // Attribute types
823                 //
824                 obsolete_attribute_type = CoreLookupType ("System.ObsoleteAttribute");
825                 conditional_attribute_type = CoreLookupType ("System.Diagnostics.ConditionalAttribute");
826
827                 //
828                 // When compiling corlib, store the "real" types here.
829                 //
830                 if (!RootContext.StdLib) {
831                         system_int32_type = typeof (System.Int32);
832                         system_array_type = typeof (System.Array);
833                         system_type_type = typeof (System.Type);
834                         system_assemblybuilder_type = typeof (System.Reflection.Emit.AssemblyBuilder);
835
836                         Type [] void_arg = {  };
837                         system_int_array_get_length = GetMethod (
838                                 system_array_type, "get_Length", void_arg);
839                         system_int_array_get_rank = GetMethod (
840                                 system_array_type, "get_Rank", void_arg);
841                         system_object_array_clone = GetMethod (
842                                 system_array_type, "Clone", void_arg);
843
844                         Type [] system_int_arg = { system_int32_type };
845                         system_int_array_get_length_int = GetMethod (
846                                 system_array_type, "GetLength", system_int_arg);
847                         system_int_array_get_upper_bound_int = GetMethod (
848                                 system_array_type, "GetUpperBound", system_int_arg);
849                         system_int_array_get_lower_bound_int = GetMethod (
850                                 system_array_type, "GetLowerBound", system_int_arg);
851
852                         Type [] system_array_int_arg = { system_array_type, system_int32_type };
853                         system_void_array_copyto_array_int = GetMethod (
854                                 system_array_type, "CopyTo", system_array_int_arg);
855
856                         Type [] system_type_type_arg = { system_type_type, system_type_type, system_type_type };
857
858                         try {
859                         system_void_set_corlib_type_builders = GetMethod (
860                                 system_assemblybuilder_type, "SetCorlibTypeBuilders",
861                                 system_type_type_arg);
862
863                         object[] args = new object [3];
864                         args [0] = object_type;
865                         args [1] = value_type;
866                         args [2] = enum_type;
867
868                         system_void_set_corlib_type_builders.Invoke (CodeGen.AssemblyBuilder, args);
869                         } catch {
870                                 Console.WriteLine ("Corlib compilation is not supported in Microsoft.NET due to bugs in it");
871                         }
872                 }
873         }
874
875         //
876         // The helper methods that are used by the compiler
877         //
878         public static void InitCodeHelpers ()
879         {
880                 //
881                 // Now load the default methods that we use.
882                 //
883                 Type [] string_string = { string_type, string_type };
884                 string_concat_string_string = GetMethod (
885                         string_type, "Concat", string_string);
886
887                 Type [] object_object = { object_type, object_type };
888                 string_concat_object_object = GetMethod (
889                         string_type, "Concat", object_object);
890
891                 Type [] string_ = { string_type };
892                 string_isinterneted_string = GetMethod (
893                         string_type, "IsInterned", string_);
894                 
895                 Type [] runtime_type_handle = { runtime_handle_type };
896                 system_type_get_type_from_handle = GetMethod (
897                         type_type, "GetTypeFromHandle", runtime_type_handle);
898
899                 Type [] delegate_delegate = { delegate_type, delegate_type };
900                 delegate_combine_delegate_delegate = GetMethod (
901                                 delegate_type, "Combine", delegate_delegate);
902
903                 delegate_remove_delegate_delegate = GetMethod (
904                                 delegate_type, "Remove", delegate_delegate);
905
906                 //
907                 // Void arguments
908                 //
909                 Type [] void_arg = {  };
910                 object_getcurrent_void = GetMethod (
911                         ienumerator_type, "get_Current", void_arg);
912                 bool_movenext_void = GetMethod (
913                         ienumerator_type, "MoveNext", void_arg);
914                 void_dispose_void = GetMethod (
915                         idisposable_type, "Dispose", void_arg);
916                 int_get_offset_to_string_data = GetMethod (
917                         runtime_helpers_type, "get_OffsetToStringData", void_arg);
918                 int_array_get_length = GetMethod (
919                         array_type, "get_Length", void_arg);
920                 int_array_get_rank = GetMethod (
921                         array_type, "get_Rank", void_arg);
922
923                 //
924                 // Int32 arguments
925                 //
926                 Type [] int_arg = { int32_type };
927                 int_array_get_length_int = GetMethod (
928                         array_type, "GetLength", int_arg);
929                 int_array_get_upper_bound_int = GetMethod (
930                         array_type, "GetUpperBound", int_arg);
931                 int_array_get_lower_bound_int = GetMethod (
932                         array_type, "GetLowerBound", int_arg);
933
934                 //
935                 // System.Array methods
936                 //
937                 object_array_clone = GetMethod (
938                         array_type, "Clone", void_arg);
939                 Type [] array_int_arg = { array_type, int32_type };
940                 void_array_copyto_array_int = GetMethod (
941                         array_type, "CopyTo", array_int_arg);
942                 
943                 //
944                 // object arguments
945                 //
946                 Type [] object_arg = { object_type };
947                 void_monitor_enter_object = GetMethod (
948                         monitor_type, "Enter", object_arg);
949                 void_monitor_exit_object = GetMethod (
950                         monitor_type, "Exit", object_arg);
951
952                 Type [] array_field_handle_arg = { array_type, runtime_field_handle_type };
953                 
954                 void_initializearray_array_fieldhandle = GetMethod (
955                         runtime_helpers_type, "InitializeArray", array_field_handle_arg);
956
957                 //
958                 // Array functions
959                 //
960                 int_getlength_int = GetMethod (
961                         array_type, "GetLength", int_arg);
962
963                 //
964                 // Decimal constructors
965                 //
966                 Type [] dec_arg = { int32_type, int32_type, int32_type, bool_type, byte_type };
967                 void_decimal_ctor_five_args = GetConstructor (
968                         decimal_type, dec_arg);
969                 
970                 //
971                 // Attributes
972                 //
973                 cons_param_array_attribute = GetConstructor (
974                         param_array_type, void_arg);
975
976                 unverifiable_code_ctor = GetConstructor (
977                         unverifiable_code_type, void_arg);
978                 
979         }
980
981         const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance;
982
983         static Hashtable type_hash = new Hashtable ();
984
985         /// <remarks>
986         ///   This is the "old", non-cache based FindMembers() function.  We cannot use
987         ///   the cache here because there is no member name argument.
988         /// </remarks>
989         public static MemberList FindMembers (Type t, MemberTypes mt, BindingFlags bf,
990                                               MemberFilter filter, object criteria)
991         {
992                 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
993
994                 //
995                 // `builder_to_declspace' contains all dynamic types.
996                 //
997                 if (decl != null) {
998                         MemberList list;
999                         Timer.StartTimer (TimerType.FindMembers);
1000                         list = decl.FindMembers (mt, bf, filter, criteria);
1001                         Timer.StopTimer (TimerType.FindMembers);
1002                         return list;
1003                 }
1004
1005                 //
1006                 // We have to take care of arrays specially, because GetType on
1007                 // a TypeBuilder array will return a Type, not a TypeBuilder,
1008                 // and we can not call FindMembers on this type.
1009                 //
1010                 if (t.IsSubclassOf (TypeManager.array_type))
1011                         return new MemberList (TypeManager.array_type.FindMembers (mt, bf, filter, criteria));
1012
1013                 //
1014                 // Since FindMembers will not lookup both static and instance
1015                 // members, we emulate this behaviour here.
1016                 //
1017                 if ((bf & instance_and_static) == instance_and_static){
1018                         MemberInfo [] i_members = t.FindMembers (
1019                                 mt, bf & ~BindingFlags.Static, filter, criteria);
1020
1021                         int i_len = i_members.Length;
1022                         if (i_len == 1){
1023                                 MemberInfo one = i_members [0];
1024
1025                                 //
1026                                 // If any of these are present, we are done!
1027                                 //
1028                                 if ((one is Type) || (one is EventInfo) || (one is FieldInfo))
1029                                         return new MemberList (i_members);
1030                         }
1031                                 
1032                         MemberInfo [] s_members = t.FindMembers (
1033                                 mt, bf & ~BindingFlags.Instance, filter, criteria);
1034
1035                         int s_len = s_members.Length;
1036                         if (i_len > 0 || s_len > 0)
1037                                 return new MemberList (i_members, s_members);
1038                         else {
1039                                 if (i_len > 0)
1040                                         return new MemberList (i_members);
1041                                 else
1042                                         return new MemberList (s_members);
1043                         }
1044                 }
1045
1046                 return new MemberList (t.FindMembers (mt, bf, filter, criteria));
1047         }
1048
1049
1050         /// <summary>
1051         ///   This method is only called from within MemberLookup.  It tries to use the member
1052         ///   cache if possible and falls back to the normal FindMembers if not.  The `used_cache'
1053         ///   flag tells the caller whether we used the cache or not.  If we used the cache, then
1054         ///   our return value will already contain all inherited members and the caller don't need
1055         ///   to check base classes and interfaces anymore.
1056         /// </summary>
1057         private static MemberList MemberLookup_FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1058                                                             string name, out bool used_cache)
1059         {
1060                 //
1061                 // We have to take care of arrays specially, because GetType on
1062                 // a TypeBuilder array will return a Type, not a TypeBuilder,
1063                 // and we can not call FindMembers on this type.
1064                 //
1065                 if (t.IsSubclassOf (TypeManager.array_type)) {
1066                         used_cache = true;
1067                         return TypeHandle.ArrayType.MemberCache.FindMembers (
1068                                 mt, bf, name, FilterWithClosure_delegate, null);
1069                 }
1070
1071                 //
1072                 // If this is a dynamic type, it's always in the `builder_to_declspace' hash table
1073                 // and we can ask the DeclSpace for the MemberCache.
1074                 //
1075                 if (t is TypeBuilder) {
1076                         DeclSpace decl = (DeclSpace) builder_to_declspace [t];
1077                         MemberCache cache = decl.MemberCache;
1078
1079                         //
1080                         // If this DeclSpace has a MemberCache, use it.
1081                         //
1082
1083                         if (cache != null) {
1084                                 used_cache = true;
1085                                 return cache.FindMembers (
1086                                         mt, bf, name, FilterWithClosure_delegate, null);
1087                         }
1088
1089                         // If there is no MemberCache, we need to use the "normal" FindMembers.
1090
1091                         MemberList list;
1092                         Timer.StartTimer (TimerType.FindMembers);
1093                         list = decl.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
1094                                                  FilterWithClosure_delegate, name);
1095                         Timer.StopTimer (TimerType.FindMembers);
1096                         used_cache = false;
1097                         return list;
1098                 }
1099
1100                 //
1101                 // This call will always succeed.  There is exactly one TypeHandle instance per
1102                 // type, TypeHandle.GetTypeHandle() will either return it or create a new one
1103                 // if it didn't already exist.
1104                 //
1105                 TypeHandle handle = TypeHandle.GetTypeHandle (t);
1106
1107                 used_cache = true;
1108                 return handle.MemberCache.FindMembers (mt, bf, name, FilterWithClosure_delegate, null);
1109         }
1110
1111         public static bool IsBuiltinType (Type t)
1112         {
1113                 if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
1114                     t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1115                     t == char_type || t == short_type || t == decimal_type || t == bool_type ||
1116                     t == sbyte_type || t == byte_type || t == ushort_type || t == void_type)
1117                         return true;
1118                 else
1119                         return false;
1120         }
1121
1122         public static bool IsDelegateType (Type t)
1123         {
1124                 if (t.IsSubclassOf (TypeManager.delegate_type))
1125                         return true;
1126                 else
1127                         return false;
1128         }
1129         
1130         public static bool IsEnumType (Type t)
1131         {
1132                 if (t.IsSubclassOf (TypeManager.enum_type))
1133                         return true;
1134                 else
1135                         return false;
1136         }
1137
1138         //
1139         // Whether a type is unmanaged.  This is used by the unsafe code (25.2)
1140         //
1141         public static bool IsUnmanagedType (Type t)
1142         {
1143                 if (IsBuiltinType (t) && t != TypeManager.string_type)
1144                         return true;
1145
1146                 if (IsEnumType (t))
1147                         return true;
1148
1149                 if (t.IsPointer)
1150                         return true;
1151
1152                 if (IsValueType (t)){
1153                         if (t is TypeBuilder){
1154                                 TypeContainer tc = LookupTypeContainer (t);
1155
1156                                 foreach (Field f in tc.Fields){
1157                                         if (f.FieldBuilder.IsStatic)
1158                                                 continue;
1159                                         if (!IsUnmanagedType (f.FieldBuilder.FieldType))
1160                                                 return false;
1161                                 }
1162                         } else {
1163                                 FieldInfo [] fields = t.GetFields ();
1164
1165                                 foreach (FieldInfo f in fields){
1166                                         if (f.IsStatic)
1167                                                 continue;
1168                                         if (!IsUnmanagedType (f.FieldType))
1169                                                 return false;
1170                                 }
1171                         }
1172                         return true;
1173                 }
1174
1175                 return false;
1176         }
1177                 
1178         public static bool IsValueType (Type t)
1179         {
1180                 if (t.IsSubclassOf (TypeManager.value_type))
1181                         return true;
1182                 else
1183                         return false;
1184         }
1185         
1186         public static bool IsInterfaceType (Type t)
1187         {
1188                 Interface iface = builder_to_declspace [t] as Interface;
1189
1190                 if (iface != null)
1191                         return true;
1192                 else
1193                         return false;
1194         }
1195
1196         //
1197         // Checks whether `type' is a subclass or nested child of `parent'.
1198         //
1199         public static bool IsSubclassOrNestedChildOf (Type type, Type parent)
1200         {
1201                 do {
1202                         if ((type == parent) || type.IsSubclassOf (parent))
1203                                 return true;
1204
1205                         // Handle nested types.
1206                         type = type.DeclaringType;
1207                 } while (type != null);
1208
1209                 return false;
1210         }
1211
1212         //
1213         // Checks whether `type' is a nested child of `parent'.
1214         //
1215         public static bool IsNestedChildOf (Type type, Type parent)
1216         {
1217                 if ((type == parent) || type.IsSubclassOf (parent))
1218                         return false;
1219                 else
1220                         return IsSubclassOrNestedChildOf (type, parent);
1221         }
1222
1223         /// <summary>
1224         ///   Returns the User Defined Types
1225         /// </summary>
1226         public static ArrayList UserTypes {
1227                 get {
1228                         return user_types;
1229                 }
1230         }
1231
1232         public static Hashtable TypeContainers {
1233                 get {
1234                         return typecontainers;
1235                 }
1236         }
1237
1238         static Hashtable builder_to_constant;
1239
1240         public static void RegisterConstant (FieldBuilder fb, Const c)
1241         {
1242                 if (builder_to_constant == null)
1243                         builder_to_constant = new PtrHashtable ();
1244
1245                 if (builder_to_constant.Contains (fb))
1246                         return;
1247
1248                 builder_to_constant.Add (fb, c);
1249         }
1250
1251         public static Const LookupConstant (FieldBuilder fb)
1252         {
1253                 if (builder_to_constant == null)
1254                         return null;
1255                 
1256                 return (Const) builder_to_constant [fb];
1257         }
1258         
1259         /// <summary>
1260         ///   Gigantic work around for missing features in System.Reflection.Emit follows.
1261         /// </summary>
1262         ///
1263         /// <remarks>
1264         ///   Since System.Reflection.Emit can not return MethodBase.GetParameters
1265         ///   for anything which is dynamic, and we need this in a number of places,
1266         ///   we register this information here, and use it afterwards.
1267         /// </remarks>
1268         static public bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] args)
1269         {
1270                 if (args == null)
1271                         args = NoTypes;
1272                                 
1273                 method_arguments.Add (mb, args);
1274                 method_internal_params.Add (mb, ip);
1275                 
1276                 return true;
1277         }
1278         
1279         static public InternalParameters LookupParametersByBuilder (MethodBase mb)
1280         {
1281                 if (! (mb is ConstructorBuilder || mb is MethodBuilder))
1282                         return null;
1283                 
1284                 if (method_internal_params.Contains (mb))
1285                         return (InternalParameters) method_internal_params [mb];
1286                 else
1287                         throw new Exception ("Argument for Method not registered" + mb);
1288         }
1289
1290         /// <summary>
1291         ///    Returns the argument types for a method based on its methodbase
1292         ///
1293         ///    For dynamic methods, we use the compiler provided types, for
1294         ///    methods from existing assemblies we load them from GetParameters,
1295         ///    and insert them into the cache
1296         /// </summary>
1297         static public Type [] GetArgumentTypes (MethodBase mb)
1298         {
1299                 if (method_arguments.Contains (mb))
1300                         return (Type []) method_arguments [mb];
1301                 else {
1302                         ParameterInfo [] pi = mb.GetParameters ();
1303                         int c = pi.Length;
1304                         Type [] types = new Type [c];
1305                         
1306                         for (int i = 0; i < c; i++)
1307                                 types [i] = pi [i].ParameterType;
1308
1309                         method_arguments.Add (mb, types);
1310                         return types;
1311                 }
1312         }
1313
1314         /// <summary>
1315         ///    Returns the argument types for an indexer based on its PropertyInfo
1316         ///
1317         ///    For dynamic indexers, we use the compiler provided types, for
1318         ///    indexers from existing assemblies we load them from GetParameters,
1319         ///    and insert them into the cache
1320         /// </summary>
1321         static public Type [] GetArgumentTypes (PropertyInfo indexer)
1322         {
1323                 if (indexer_arguments.Contains (indexer))
1324                         return (Type []) indexer_arguments [indexer];
1325                 else if (indexer is PropertyBuilder)
1326                         // If we're a PropertyBuilder and not in the
1327                         // `indexer_arguments' hash, then we're a property and
1328                         // not an indexer.
1329                         return NoTypes;
1330                 else {
1331                         ParameterInfo [] pi = indexer.GetIndexParameters ();
1332                         // Property, not an indexer.
1333                         if (pi == null)
1334                                 return NoTypes;
1335                         int c = pi.Length;
1336                         Type [] types = new Type [c];
1337                         
1338                         for (int i = 0; i < c; i++)
1339                                 types [i] = pi [i].ParameterType;
1340
1341                         indexer_arguments.Add (indexer, types);
1342                         return types;
1343                 }
1344         }
1345         
1346         // <remarks>
1347         //  This is a workaround the fact that GetValue is not
1348         //  supported for dynamic types
1349         // </remarks>
1350         static Hashtable fields = new Hashtable ();
1351         static public bool RegisterFieldValue (FieldBuilder fb, object value)
1352         {
1353                 if (fields.Contains (fb))
1354                         return false;
1355
1356                 fields.Add (fb, value);
1357
1358                 return true;
1359         }
1360
1361         static public object GetValue (FieldBuilder fb)
1362         {
1363                 return fields [fb];
1364         }
1365
1366         static Hashtable fieldbuilders_to_fields = new Hashtable ();
1367         static public bool RegisterFieldBase (FieldBuilder fb, FieldBase f)
1368         {
1369                 if (fieldbuilders_to_fields.Contains (fb))
1370                         return false;
1371
1372                 fieldbuilders_to_fields.Add (fb, f);
1373                 return true;
1374         }
1375
1376         static public FieldBase GetField (FieldInfo fb)
1377         {
1378                 return (FieldBase) fieldbuilders_to_fields [fb];
1379         }
1380         
1381         static Hashtable events;
1382
1383         static public bool RegisterEvent (MyEventBuilder eb, MethodBase add, MethodBase remove)
1384         {
1385                 if (events == null)
1386                         events = new Hashtable ();
1387
1388                 if (events.Contains (eb))
1389                         return false;
1390
1391                 events.Add (eb, new Pair (add, remove));
1392
1393                 return true;
1394         }
1395
1396         static public MethodInfo GetAddMethod (EventInfo ei)
1397         {
1398                 if (ei is MyEventBuilder) {
1399                         Pair pair = (Pair) events [ei];
1400
1401                         return (MethodInfo) pair.First;
1402                 } else
1403                         return ei.GetAddMethod ();
1404         }
1405
1406         static public MethodInfo GetRemoveMethod (EventInfo ei)
1407         {
1408                 if (ei is MyEventBuilder) {
1409                         Pair pair = (Pair) events [ei];
1410
1411                         return (MethodInfo) pair.Second;
1412                 } else
1413                         return ei.GetAddMethod ();
1414         }
1415
1416         static Hashtable priv_fields_events;
1417
1418         static public bool RegisterPrivateFieldOfEvent (EventInfo einfo, FieldBuilder builder)
1419         {
1420                 if (priv_fields_events == null)
1421                         priv_fields_events = new Hashtable ();
1422
1423                 if (priv_fields_events.Contains (einfo))
1424                         return false;
1425
1426                 priv_fields_events.Add (einfo, builder);
1427
1428                 return true;
1429         }
1430
1431         static public MemberInfo GetPrivateFieldOfEvent (EventInfo ei)
1432         {
1433                 return (MemberInfo) priv_fields_events [ei];
1434         }
1435                 
1436         static Hashtable properties;
1437         
1438         static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set)
1439         {
1440                 if (properties == null)
1441                         properties = new Hashtable ();
1442
1443                 if (properties.Contains (pb))
1444                         return false;
1445
1446                 properties.Add (pb, new Pair (get, set));
1447
1448                 return true;
1449         }
1450
1451         static public bool RegisterIndexer (PropertyBuilder pb, MethodBase get, MethodBase set, Type[] args)
1452         {
1453                 if (!RegisterProperty (pb, get,set))
1454                         return false;
1455
1456                 indexer_arguments.Add (pb, args);
1457
1458                 return true;
1459         }
1460
1461         /// <summary>
1462         ///   Given an array of interface types, expand and eliminate repeated ocurrences
1463         ///   of an interface.  
1464         /// </summary>
1465         ///
1466         /// <remarks>
1467         ///   This expands in context like: IA; IB : IA; IC : IA, IB; the interface "IC" to
1468         ///   be IA, IB, IC.
1469         /// </remarks>
1470         public static Type [] ExpandInterfaces (Type [] base_interfaces)
1471         {
1472                 ArrayList new_ifaces = new ArrayList ();
1473                 
1474                 foreach (Type iface in base_interfaces){
1475                         if (!new_ifaces.Contains (iface))
1476                                 new_ifaces.Add (iface);
1477                         
1478                         Type [] implementing = TypeManager.GetInterfaces (iface);
1479                         
1480                         foreach (Type imp in implementing){
1481                                 if (!new_ifaces.Contains (imp))
1482                                         new_ifaces.Add (imp);
1483                         }
1484                 }
1485                 Type [] ret = new Type [new_ifaces.Count];
1486                 new_ifaces.CopyTo (ret, 0);
1487                 return ret;
1488         }
1489                 
1490         /// <summary>
1491         ///   This function returns the interfaces in the type `t'.  Works with
1492         ///   both types and TypeBuilders.
1493         /// </summary>
1494         public static Type [] GetInterfaces (Type t)
1495         {
1496                 //
1497                 // The reason for catching the Array case is that Reflection.Emit
1498                 // will not return a TypeBuilder for Array types of TypeBuilder types,
1499                 // but will still throw an exception if we try to call GetInterfaces
1500                 // on the type.
1501                 //
1502                 // Since the array interfaces are always constant, we return those for
1503                 // the System.Array
1504                 //
1505                 
1506                 if (t.IsArray)
1507                         t = TypeManager.array_type;
1508                 
1509                 if (t is TypeBuilder){
1510                         Type [] parent_ifaces;
1511                         
1512                         if (t.BaseType == null)
1513                                 parent_ifaces = NoTypes;
1514                         else
1515                                 parent_ifaces = GetInterfaces (t.BaseType);
1516                         Type [] type_ifaces = (Type []) builder_to_ifaces [t];
1517                         if (type_ifaces == null)
1518                                 type_ifaces = NoTypes;
1519
1520                         int parent_count = parent_ifaces.Length;
1521                         Type [] result = new Type [parent_count + type_ifaces.Length];
1522                         parent_ifaces.CopyTo (result, 0);
1523                         type_ifaces.CopyTo (result, parent_count);
1524
1525                         return result;
1526                 } else
1527                         return t.GetInterfaces ();
1528         }
1529         
1530         /// <remarks>
1531         ///  The following is used to check if a given type implements an interface.
1532         ///  The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
1533         /// </remarks>
1534         public static bool ImplementsInterface (Type t, Type iface)
1535         {
1536                 Type [] interfaces;
1537
1538                 //
1539                 // FIXME OPTIMIZATION:
1540                 // as soon as we hit a non-TypeBuiler in the interface
1541                 // chain, we could return, as the `Type.GetInterfaces'
1542                 // will return all the interfaces implement by the type
1543                 // or its parents.
1544                 //
1545                 do {
1546                         interfaces = GetInterfaces (t);
1547
1548                         if (interfaces != null){
1549                                 foreach (Type i in interfaces){
1550                                         if (i == iface)
1551                                                 return true;
1552                                 }
1553                         }
1554                         
1555                         t = t.BaseType;
1556                 } while (t != null);
1557                 
1558                 return false;
1559         }
1560
1561         // This is a custom version of Convert.ChangeType() which works
1562         // with the TypeBuilder defined types when compiling corlib.
1563         public static object ChangeType (object value, Type conversionType)
1564         {
1565                 if (!(value is IConvertible))
1566                         throw new ArgumentException ();
1567
1568                 IConvertible convertValue = (IConvertible) value;
1569                 CultureInfo ci = CultureInfo.CurrentCulture;
1570                 NumberFormatInfo provider = ci.NumberFormat;
1571
1572                 //
1573                 // We must use Type.Equals() here since `conversionType' is
1574                 // the TypeBuilder created version of a system type and not
1575                 // the system type itself.  You cannot use Type.GetTypeCode()
1576                 // on such a type - it'd always return TypeCode.Object.
1577                 //
1578                 if (conversionType.Equals (typeof (Boolean)))
1579                         return (object)(convertValue.ToBoolean (provider));
1580                 else if (conversionType.Equals (typeof (Byte)))
1581                         return (object)(convertValue.ToByte (provider));
1582                 else if (conversionType.Equals (typeof (Char)))
1583                         return (object)(convertValue.ToChar (provider));
1584                 else if (conversionType.Equals (typeof (DateTime)))
1585                         return (object)(convertValue.ToDateTime (provider));
1586                 else if (conversionType.Equals (typeof (Decimal)))
1587                         return (object)(convertValue.ToDecimal (provider));
1588                 else if (conversionType.Equals (typeof (Double)))
1589                         return (object)(convertValue.ToDouble (provider));
1590                 else if (conversionType.Equals (typeof (Int16)))
1591                         return (object)(convertValue.ToInt16 (provider));
1592                 else if (conversionType.Equals (typeof (Int32)))
1593                         return (object)(convertValue.ToInt32 (provider));
1594                 else if (conversionType.Equals (typeof (Int64)))
1595                         return (object)(convertValue.ToInt64 (provider));
1596                 else if (conversionType.Equals (typeof (SByte)))
1597                         return (object)(convertValue.ToSByte (provider));
1598                 else if (conversionType.Equals (typeof (Single)))
1599                         return (object)(convertValue.ToSingle (provider));
1600                 else if (conversionType.Equals (typeof (String)))
1601                         return (object)(convertValue.ToString (provider));
1602                 else if (conversionType.Equals (typeof (UInt16)))
1603                         return (object)(convertValue.ToUInt16 (provider));
1604                 else if (conversionType.Equals (typeof (UInt32)))
1605                         return (object)(convertValue.ToUInt32 (provider));
1606                 else if (conversionType.Equals (typeof (UInt64)))
1607                         return (object)(convertValue.ToUInt64 (provider));
1608                 else if (conversionType.Equals (typeof (Object)))
1609                         return (object)(value);
1610                 else 
1611                         throw new InvalidCastException ();
1612         }
1613
1614         //
1615         // This is needed, because enumerations from assemblies
1616         // do not report their underlyingtype, but they report
1617         // themselves
1618         //
1619         public static Type EnumToUnderlying (Type t)
1620         {
1621                 if (t == TypeManager.enum_type)
1622                         return t;
1623
1624                 t = t.UnderlyingSystemType;
1625                 if (!TypeManager.IsEnumType (t))
1626                         return t;
1627         
1628                 if (t is TypeBuilder) {
1629                         // slow path needed to compile corlib
1630                         if (t == TypeManager.bool_type ||
1631                                         t == TypeManager.byte_type ||
1632                                         t == TypeManager.sbyte_type ||
1633                                         t == TypeManager.char_type ||
1634                                         t == TypeManager.short_type ||
1635                                         t == TypeManager.ushort_type ||
1636                                         t == TypeManager.int32_type ||
1637                                         t == TypeManager.uint32_type ||
1638                                         t == TypeManager.int64_type ||
1639                                         t == TypeManager.uint64_type)
1640                                 return t;
1641                         throw new Exception ("Unhandled typecode in enum " + " from " + t.AssemblyQualifiedName);
1642                 }
1643                 TypeCode tc = Type.GetTypeCode (t);
1644
1645                 switch (tc){
1646                 case TypeCode.Boolean:
1647                         return TypeManager.bool_type;
1648                 case TypeCode.Byte:
1649                         return TypeManager.byte_type;
1650                 case TypeCode.SByte:
1651                         return TypeManager.sbyte_type;
1652                 case TypeCode.Char:
1653                         return TypeManager.char_type;
1654                 case TypeCode.Int16:
1655                         return TypeManager.short_type;
1656                 case TypeCode.UInt16:
1657                         return TypeManager.ushort_type;
1658                 case TypeCode.Int32:
1659                         return TypeManager.int32_type;
1660                 case TypeCode.UInt32:
1661                         return TypeManager.uint32_type;
1662                 case TypeCode.Int64:
1663                         return TypeManager.int64_type;
1664                 case TypeCode.UInt64:
1665                         return TypeManager.uint64_type;
1666                 }
1667                 throw new Exception ("Unhandled typecode in enum " + tc + " from " + t.AssemblyQualifiedName);
1668         }
1669
1670         //
1671         // When compiling corlib and called with one of the core types, return
1672         // the corresponding typebuilder for that type.
1673         //
1674         public static Type TypeToCoreType (Type t)
1675         {
1676                 if (RootContext.StdLib || (t is TypeBuilder))
1677                         return t;
1678
1679                 TypeCode tc = Type.GetTypeCode (t);
1680
1681                 switch (tc){
1682                 case TypeCode.Boolean:
1683                         return TypeManager.bool_type;
1684                 case TypeCode.Byte:
1685                         return TypeManager.byte_type;
1686                 case TypeCode.SByte:
1687                         return TypeManager.sbyte_type;
1688                 case TypeCode.Char:
1689                         return TypeManager.char_type;
1690                 case TypeCode.Int16:
1691                         return TypeManager.short_type;
1692                 case TypeCode.UInt16:
1693                         return TypeManager.ushort_type;
1694                 case TypeCode.Int32:
1695                         return TypeManager.int32_type;
1696                 case TypeCode.UInt32:
1697                         return TypeManager.uint32_type;
1698                 case TypeCode.Int64:
1699                         return TypeManager.int64_type;
1700                 case TypeCode.UInt64:
1701                         return TypeManager.uint64_type;
1702                 case TypeCode.String:
1703                         return TypeManager.string_type;
1704                 default:
1705                         if (t == typeof (void))
1706                                 return TypeManager.void_type;
1707                         if (t == typeof (object))
1708                                 return TypeManager.object_type;
1709                         if (t == typeof (System.Type))
1710                                 return TypeManager.type_type;
1711                         return t;
1712                 }
1713         }
1714
1715         /// <summary>
1716         ///   Utility function that can be used to probe whether a type
1717         ///   is managed or not.  
1718         /// </summary>
1719         public static bool VerifyUnManaged (Type t, Location loc)
1720         {
1721                 if (t.IsValueType || t.IsPointer){
1722                         //
1723                         // FIXME: this is more complex, we actually need to
1724                         // make sure that the type does not contain any
1725                         // classes itself
1726                         //
1727                         return true;
1728                 }
1729
1730                 if (!RootContext.StdLib && (t == TypeManager.decimal_type))
1731                         // We need this explicit check here to make it work when
1732                         // compiling corlib.
1733                         return true;
1734
1735                 Report.Error (
1736                         208, loc,
1737                         "Cannot take the address or size of a variable of a managed type ('" +
1738                         CSharpName (t) + "')");
1739                 return false;   
1740         }
1741         
1742         /// <summary>
1743         ///   Returns the name of the indexer in a given type.
1744         /// </summary>
1745         /// <remarks>
1746         ///   The default is not always `Item'.  The user can change this behaviour by
1747         ///   using the DefaultMemberAttribute in the class.
1748         ///
1749         ///   For example, the String class indexer is named `Chars' not `Item' 
1750         /// </remarks>
1751         public static string IndexerPropertyName (Type t)
1752         {
1753                 if (t is TypeBuilder) {
1754                         if (t.IsInterface) {
1755                                 Interface i = LookupInterface (t);
1756
1757                                 if ((i == null) || (i.IndexerName == null))
1758                                         return "Item";
1759
1760                                 return i.IndexerName;
1761                         } else {
1762                                 TypeContainer tc = LookupTypeContainer (t);
1763
1764                                 if ((tc == null) || (tc.IndexerName == null))
1765                                         return "Item";
1766
1767                                 return tc.IndexerName;
1768                         }
1769                 }
1770                 
1771                 System.Attribute attr = System.Attribute.GetCustomAttribute (
1772                         t, TypeManager.default_member_type);
1773                 if (attr != null){
1774                         DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
1775                         return dma.MemberName;
1776                 }
1777
1778                 return "Item";
1779         }
1780
1781         public static void MakePinned (LocalBuilder builder)
1782         {
1783                 //
1784                 // FIXME: Flag the "LocalBuilder" type as being
1785                 // pinned.  Figure out API.
1786                 //
1787         }
1788
1789
1790         //
1791         // Returns whether the array of memberinfos contains the given method
1792         //
1793         static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method)
1794         {
1795                 Type [] new_args = TypeManager.GetArgumentTypes (new_method);
1796                 
1797                 foreach (MethodBase method in array){
1798                         if (method.Name != new_method.Name)
1799                                 continue;
1800                         
1801                         Type [] old_args = TypeManager.GetArgumentTypes (method);
1802                         int old_count = old_args.Length;
1803                         int i;
1804                         
1805                         if (new_args.Length != old_count)
1806                                 continue;
1807                         
1808                         for (i = 0; i < old_count; i++){
1809                                 if (old_args [i] != new_args [i])
1810                                         break;
1811                         }
1812                         if (i != old_count)
1813                                 continue;
1814
1815                         return true;
1816                 }
1817                 return false;
1818         }
1819         
1820         //
1821         // We copy methods from `new_members' into `target_list' if the signature
1822         // for the method from in the new list does not exist in the target_list
1823         //
1824         // The name is assumed to be the same.
1825         //
1826         public static ArrayList CopyNewMethods (ArrayList target_list, MemberList new_members)
1827         {
1828                 if (target_list == null){
1829                         target_list = new ArrayList ();
1830
1831                         foreach (MemberInfo mi in new_members){
1832                                 if (mi is MethodBase)
1833                                         target_list.Add (mi);
1834                         }
1835                         return target_list;
1836                 }
1837                 
1838                 MemberInfo [] target_array = new MemberInfo [target_list.Count];
1839                 target_list.CopyTo (target_array, 0);
1840                 
1841                 foreach (MemberInfo mi in new_members){
1842                         MethodBase new_method = (MethodBase) mi;
1843                         
1844                         if (!ArrayContainsMethod (target_array, new_method))
1845                                 target_list.Add (new_method);
1846                 }
1847                 return target_list;
1848         }
1849
1850         [Flags]
1851         public enum MethodFlags {
1852                 IsObsolete = 1,
1853                 IsObsoleteError = 2,
1854                 ShouldIgnore = 3
1855         }
1856         
1857         //
1858         // Returns the TypeManager.MethodFlags for this method.
1859         // This emits an error 619 / warning 618 if the method is obsolete.
1860         // In the former case, TypeManager.MethodFlags.IsObsoleteError is returned.
1861         //
1862         static public MethodFlags GetMethodFlags (MethodBase mb, Location loc)
1863         {
1864                 MethodFlags flags = 0;
1865                 
1866                 if (mb.DeclaringType is TypeBuilder){
1867                         MethodData method = (MethodData) builder_to_method [mb];
1868                         if (method == null) {
1869                                 // FIXME: implement Obsolete attribute on Property,
1870                                 //        Indexer and Event.
1871                                 return 0;
1872                         }
1873
1874                         return method.GetMethodFlags (loc);
1875                 }
1876
1877                 object [] attrs = mb.GetCustomAttributes (true);
1878                 foreach (object ta in attrs){
1879                         if (!(ta is System.Attribute)){
1880                                 Console.WriteLine ("Unknown type in GetMethodFlags: " + ta);
1881                                 continue;
1882                         }
1883                         System.Attribute a = (System.Attribute) ta;
1884                         if (a.TypeId == TypeManager.obsolete_attribute_type){
1885                                 ObsoleteAttribute oa = (ObsoleteAttribute) a;
1886
1887                                 string method_desc = TypeManager.CSharpSignature (mb);
1888
1889                                 if (oa.IsError) {
1890                                         Report.Error (619, loc, "Method `" + method_desc +
1891                                                       "' is obsolete: `" + oa.Message + "'");
1892                                         return MethodFlags.IsObsoleteError;
1893                                 } else
1894                                         Report.Warning (618, loc, "Method `" + method_desc +
1895                                                         "' is obsolete: `" + oa.Message + "'");
1896
1897                                 flags |= MethodFlags.IsObsolete;
1898
1899                                 continue;
1900                         }
1901                         
1902                         //
1903                         // Skip over conditional code.
1904                         //
1905                         if (a.TypeId == TypeManager.conditional_attribute_type){
1906                                 ConditionalAttribute ca = (ConditionalAttribute) a;
1907
1908                                 if (RootContext.AllDefines [ca.ConditionString] == null)
1909                                         flags |= MethodFlags.ShouldIgnore;
1910                         }
1911                 }
1912
1913                 return flags;
1914         }
1915         
1916 #region MemberLookup implementation
1917         
1918         //
1919         // Name of the member
1920         //
1921         static string   closure_name;
1922
1923         //
1924         // Whether we allow private members in the result (since FindMembers
1925         // uses NonPublic for both protected and private), we need to distinguish.
1926         //
1927         static bool     closure_private_ok;
1928
1929         //
1930         // Who is invoking us and which type is being queried currently.
1931         //
1932         static Type     closure_invocation_type;
1933         static Type     closure_queried_type;
1934         static Type     closure_start_type;
1935
1936         //
1937         // The assembly that defines the type is that is calling us
1938         //
1939         static Assembly closure_invocation_assembly;
1940
1941         //
1942         // This filter filters by name + whether it is ok to include private
1943         // members in the search
1944         //
1945         static internal bool FilterWithClosure (MemberInfo m, object filter_criteria)
1946         {
1947                 //
1948                 // Hack: we know that the filter criteria will always be in the `closure'
1949                 // fields. 
1950                 //
1951
1952                 if ((filter_criteria != null) && (m.Name != (string) filter_criteria))
1953                                 return false;
1954
1955                 if ((closure_start_type == closure_invocation_type) &&
1956                     (m.DeclaringType == closure_invocation_type))
1957                         return true;
1958
1959                 //
1960                 // Ugly: we need to find out the type of `m', and depending
1961                 // on this, tell whether we accept or not
1962                 //
1963                 if (m is MethodBase){
1964                         MethodBase mb = (MethodBase) m;
1965                         MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
1966
1967                         if (ma == MethodAttributes.Private)
1968                                 return closure_private_ok || (closure_invocation_type == m.DeclaringType);
1969
1970                         //
1971                         // FamAndAssem requires that we not only derivate, but we are on the
1972                         // same assembly.  
1973                         //
1974                         if (ma == MethodAttributes.FamANDAssem){
1975                                 if (closure_invocation_assembly != mb.DeclaringType.Assembly)
1976                                         return false;
1977                         }
1978
1979                         // Assembly and FamORAssem succeed if we're in the same assembly.
1980                         if ((ma == MethodAttributes.Assembly) || (ma == MethodAttributes.FamORAssem)){
1981                                 if (closure_invocation_assembly == mb.DeclaringType.Assembly)
1982                                         return true;
1983                         }
1984
1985                         // We already know that we aren't in the same assembly.
1986                         if (ma == MethodAttributes.Assembly)
1987                                 return false;
1988
1989                         // Family and FamANDAssem require that we derive.
1990                         if ((ma == MethodAttributes.Family) || (ma == MethodAttributes.FamANDAssem)){
1991                                 if (closure_invocation_type == null)
1992                                         return false;
1993
1994                                 if (!IsSubclassOrNestedChildOf (closure_invocation_type, mb.DeclaringType))
1995                                         return false;
1996
1997                                 return true;
1998                         }
1999
2000                         // Public.
2001                         return true;
2002                 }
2003
2004                 if (m is FieldInfo){
2005                         FieldInfo fi = (FieldInfo) m;
2006                         FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask;
2007
2008                         if (fa == FieldAttributes.Private)
2009                                 return closure_private_ok || (closure_invocation_type == m.DeclaringType);
2010
2011                         //
2012                         // FamAndAssem requires that we not only derivate, but we are on the
2013                         // same assembly.  
2014                         //
2015                         if (fa == FieldAttributes.FamANDAssem){
2016                                 if (closure_invocation_assembly != fi.DeclaringType.Assembly)
2017                                         return false;
2018                         }
2019
2020                         // Assembly and FamORAssem succeed if we're in the same assembly.
2021                         if ((fa == FieldAttributes.Assembly) || (fa == FieldAttributes.FamORAssem)){
2022                                 if (closure_invocation_assembly == fi.DeclaringType.Assembly)
2023                                         return true;
2024                         }
2025
2026                         // We already know that we aren't in the same assembly.
2027                         if (fa == FieldAttributes.Assembly)
2028                                 return false;
2029
2030                         // Family and FamANDAssem require that we derive.
2031                         if ((fa == FieldAttributes.Family) || (fa == FieldAttributes.FamANDAssem)){
2032                                 if (closure_invocation_type == null)
2033                                         return false;
2034
2035                                 if (!IsSubclassOrNestedChildOf (closure_invocation_type, fi.DeclaringType))
2036                                         return false;
2037
2038                                 // Although a derived class can access protected members of its base class
2039                                 // it cannot do so through an instance of the base class (CS1540).
2040                                 if ((closure_invocation_type != closure_start_type) &&
2041                                     closure_invocation_type.IsSubclassOf (closure_start_type))
2042                                         return false;
2043
2044                                 return true;
2045                         }
2046
2047                         // Public.
2048                         return true;
2049                 }
2050
2051                 //
2052                 // EventInfos and PropertyInfos, return true because they lack permission
2053                 // informaiton, so we need to check later on the methods.
2054                 //
2055                 return true;
2056         }
2057
2058         static MemberFilter FilterWithClosure_delegate = new MemberFilter (FilterWithClosure);
2059
2060         //
2061         // Looks up a member called `name' in the `queried_type'.  This lookup
2062         // is done by code that is contained in the definition for `invocation_type'.
2063         //
2064         // The binding flags are `bf' and the kind of members being looked up are `mt'
2065         //
2066         // Returns an array of a single element for everything but Methods/Constructors
2067         // that might return multiple matches.
2068         //
2069         public static MemberInfo [] MemberLookup (Type invocation_type, Type queried_type, 
2070                                                   MemberTypes mt, BindingFlags original_bf, string name)
2071         {
2072                 Timer.StartTimer (TimerType.MemberLookup);
2073
2074                 MemberInfo[] retval = RealMemberLookup (invocation_type, queried_type,
2075                                                         mt, original_bf, name);
2076
2077                 Timer.StopTimer (TimerType.MemberLookup);
2078
2079                 return retval;
2080         }
2081
2082         static MemberInfo [] RealMemberLookup (Type invocation_type, Type queried_type, 
2083                                                MemberTypes mt, BindingFlags original_bf, string name)
2084         {
2085                 BindingFlags bf = original_bf;
2086                 
2087                 ArrayList method_list = null;
2088                 Type current_type = queried_type;
2089                 bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0;
2090                 bool private_ok;
2091                 bool always_ok_flag = false;
2092                 bool skip_iface_check = true, used_cache = false;
2093
2094                 closure_name = name;
2095                 closure_invocation_type = invocation_type;
2096                 closure_invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
2097                 closure_start_type = queried_type;
2098
2099                 //
2100                 // If we are a nested class, we always have access to our container
2101                 // type names
2102                 //
2103                 if (invocation_type != null){
2104                         string invocation_name = invocation_type.FullName;
2105                         if (invocation_name.IndexOf ('+') != -1){
2106                                 string container = queried_type.FullName + "+";
2107                                 int container_length = container.Length;
2108                                 
2109                                 if (invocation_name.Length > container_length){
2110                                         string shared = invocation_name.Substring (0, container_length);
2111                                 
2112                                         if (shared == container)
2113                                                 always_ok_flag = true;
2114                                 }
2115                         }
2116                 }
2117                 
2118                 do {
2119                         MemberList list;
2120
2121                         //
2122                         // `NonPublic' is lame, because it includes both protected and
2123                         // private methods, so we need to control this behavior by
2124                         // explicitly tracking if a private method is ok or not.
2125                         //
2126                         // The possible cases are:
2127                         //    public, private and protected (internal does not come into the
2128                         //    equation)
2129                         //
2130                         if (invocation_type != null){
2131                                 if (invocation_type == current_type){
2132                                         private_ok = true;
2133                                 } else
2134                                         private_ok = always_ok_flag;
2135
2136                                 if (invocation_type.IsSubclassOf (current_type))
2137                                         bf = original_bf | BindingFlags.NonPublic;
2138                         } else {
2139                                 private_ok = false;
2140                                 bf = original_bf & ~BindingFlags.NonPublic;
2141                         }
2142
2143                         closure_private_ok = private_ok;
2144                         closure_queried_type = current_type;
2145
2146                         Timer.StopTimer (TimerType.MemberLookup);
2147
2148                         list = MemberLookup_FindMembers (current_type, mt, bf, name, out used_cache);
2149
2150                         Timer.StartTimer (TimerType.MemberLookup);
2151
2152                         //
2153                         // When queried for an interface type, the cache will automatically check all
2154                         // inherited members, so we don't need to do this here.  However, this only
2155                         // works if we already used the cache in the first iteration of this loop.
2156                         //
2157                         // If we used the cache in any further iteration, we can still terminate the
2158                         // loop since the cache always looks in all parent classes.
2159                         //
2160
2161                         if (used_cache)
2162                                 searching = false;
2163                         else
2164                                 skip_iface_check = false;
2165
2166                         if (current_type == TypeManager.object_type)
2167                                 searching = false;
2168                         else {
2169                                 current_type = current_type.BaseType;
2170                                 
2171                                 //
2172                                 // This happens with interfaces, they have a null
2173                                 // basetype.  Look members up in the Object class.
2174                                 //
2175                                 if (current_type == null)
2176                                         current_type = TypeManager.object_type;
2177                         }
2178                         
2179                         if (list.Count == 0)
2180                                 continue;
2181                         
2182                         //
2183                         // Events and types are returned by both `static' and `instance'
2184                         // searches, which means that our above FindMembers will
2185                         // return two copies of the same.
2186                         //
2187                         if (list.Count == 1 && !(list [0] is MethodBase)){
2188                                 return (MemberInfo []) list;
2189                         }
2190
2191                         //
2192                         // Multiple properties: we query those just to find out the indexer
2193                         // name
2194                         //
2195                         if (list [0] is PropertyInfo)
2196                                 return (MemberInfo []) list;
2197
2198                         //
2199                         // We found methods, turn the search into "method scan"
2200                         // mode.
2201                         //
2202                         
2203                         method_list = CopyNewMethods (method_list, list);
2204                         mt &= (MemberTypes.Method | MemberTypes.Constructor);
2205                 } while (searching);
2206
2207                 if (method_list != null && method_list.Count > 0)
2208                         return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
2209
2210                 //
2211                 // This happens if we already used the cache in the first iteration, in this case
2212                 // the cache already looked in all interfaces.
2213                 //
2214                 if (skip_iface_check)
2215                         return null;
2216
2217                 //
2218                 // Interfaces do not list members they inherit, so we have to
2219                 // scan those.
2220                 // 
2221                 if (!queried_type.IsInterface)
2222                         return null;
2223
2224                 if (queried_type.IsArray)
2225                         queried_type = TypeManager.array_type;
2226                 
2227                 Type [] ifaces = GetInterfaces (queried_type);
2228                 if (ifaces == null)
2229                         return null;
2230                 
2231                 foreach (Type itype in ifaces){
2232                         MemberInfo [] x;
2233
2234                         x = MemberLookup (null, itype, mt, bf, name);
2235                         if (x != null)
2236                                 return x;
2237                 }
2238                                         
2239                 return null;
2240         }
2241 #endregion
2242         
2243 }
2244
2245 /// <summary>
2246 ///   There is exactly one instance of this class per type.
2247 /// </summary>
2248 public sealed class TypeHandle : IMemberContainer {
2249         public readonly TypeHandle BaseType;
2250
2251         readonly int id = ++next_id;
2252         static int next_id = 0;
2253
2254         /// <summary>
2255         ///   Lookup a TypeHandle instance for the given type.  If the type doesn't have
2256         ///   a TypeHandle yet, a new instance of it is created.  This static method
2257         ///   ensures that we'll only have one TypeHandle instance per type.
2258         /// </summary>
2259         public static TypeHandle GetTypeHandle (Type t)
2260         {
2261                 TypeHandle handle = (TypeHandle) type_hash [t];
2262                 if (handle != null)
2263                         return handle;
2264
2265                 handle = new TypeHandle (t);
2266                 type_hash.Add (t, handle);
2267                 return handle;
2268         }
2269
2270         /// <summary>
2271         ///   Returns the TypeHandle for TypeManager.object_type.
2272         /// </summary>
2273         public static IMemberContainer ObjectType {
2274                 get {
2275                         if (object_type != null)
2276                                 return object_type;
2277
2278                         object_type = GetTypeHandle (TypeManager.object_type);
2279
2280                         return object_type;
2281                 }
2282         }
2283
2284         /// <summary>
2285         ///   Returns the TypeHandle for TypeManager.array_type.
2286         /// </summary>
2287         public static IMemberContainer ArrayType {
2288                 get {
2289                         if (array_type != null)
2290                                 return array_type;
2291
2292                         array_type = GetTypeHandle (TypeManager.array_type);
2293
2294                         return array_type;
2295                 }
2296         }
2297
2298         private static PtrHashtable type_hash = new PtrHashtable ();
2299
2300         private static TypeHandle object_type = null;
2301         private static TypeHandle array_type = null;
2302
2303         private Type type;
2304         private bool is_interface;
2305         private MemberCache member_cache;
2306
2307         private TypeHandle (Type type)
2308         {
2309                 this.type = type;
2310                 if (type.BaseType != null)
2311                         BaseType = GetTypeHandle (type.BaseType);
2312                 else if ((type != TypeManager.object_type) && (type != typeof (object)))
2313                         is_interface = true;
2314                 this.member_cache = new MemberCache (this);
2315         }
2316
2317         // IMemberContainer methods
2318
2319         public string Name {
2320                 get {
2321                         return type.FullName;
2322                 }
2323         }
2324
2325         public Type Type {
2326                 get {
2327                         return type;
2328                 }
2329         }
2330
2331         public IMemberContainer Parent {
2332                 get {
2333                         return BaseType;
2334                 }
2335         }
2336
2337         public bool IsInterface {
2338                 get {
2339                         return is_interface;
2340                 }
2341         }
2342
2343         public MemberList GetMembers (MemberTypes mt, BindingFlags bf)
2344         {
2345                 if (mt == MemberTypes.Event)
2346                         return new MemberList (type.GetEvents (bf | BindingFlags.DeclaredOnly));
2347                 else
2348                         return new MemberList (type.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
2349                                                                  null, null));
2350         }
2351
2352         // IMemberFinder methods
2353
2354         public MemberList FindMembers (MemberTypes mt, BindingFlags bf, string name,
2355                                        MemberFilter filter, object criteria)
2356         {
2357                 return member_cache.FindMembers (mt, bf, name, filter, criteria);
2358         }
2359
2360         public MemberCache MemberCache {
2361                 get {
2362                         return member_cache;
2363                 }
2364         }
2365
2366         public override string ToString ()
2367         {
2368                 if (BaseType != null)
2369                         return "TypeHandle (" + id + "," + Name + " : " + BaseType + ")";
2370                 else
2371                         return "TypeHandle (" + id + "," + Name + ")";
2372         }
2373 }
2374
2375 }