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