2002-07-22 Peter Williams <peterw@ximian.com>
[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 #define CACHE
13
14 using System;
15 using System.Globalization;
16 using System.Collections;
17 using System.Reflection;
18 using System.Reflection.Emit;
19 using System.Text.RegularExpressions;
20 using System.Runtime.CompilerServices;
21 using System.Diagnostics;
22
23 namespace Mono.CSharp {
24
25 public class TypeManager {
26         //
27         // A list of core types that the compiler requires or uses
28         //
29         static public Type object_type;
30         static public Type value_type;
31         static public Type string_type;
32         static public Type int32_type;
33         static public Type uint32_type;
34         static public Type int64_type;
35         static public Type uint64_type;
36         static public Type float_type;
37         static public Type double_type;
38         static public Type char_type;
39         static public Type char_ptr_type;
40         static public Type short_type;
41         static public Type decimal_type;
42         static public Type bool_type;
43         static public Type sbyte_type;
44         static public Type byte_type;
45         static public Type ushort_type;
46         static public Type enum_type;
47         static public Type delegate_type;
48         static public Type multicast_delegate_type;
49         static public Type void_type;
50         static public Type enumeration_type;
51         static public Type array_type;
52         static public Type runtime_handle_type;
53         static public Type icloneable_type;
54         static public Type type_type;
55         static public Type ienumerator_type;
56         static public Type idisposable_type;
57         static public Type default_member_type;
58         static public Type iasyncresult_type;
59         static public Type asynccallback_type;
60         static public Type intptr_type;
61         static public Type monitor_type;
62         static public Type runtime_field_handle_type;
63         static public Type attribute_type;
64         static public Type attribute_usage_type;
65         static public Type dllimport_type;
66         static public Type unverifiable_code_type;
67         static public Type methodimpl_attr_type;
68         static public Type marshal_as_attr_type;
69         static public Type param_array_type;
70         static public Type void_ptr_type;
71         static public Type indexer_name_type;
72         static public object obsolete_attribute_type;
73         static public object conditional_attribute_type;
74
75         static public Type [] NoTypes;
76
77         //
78         // This is only used when compiling corlib
79         //
80         static public Type system_int32_type;
81         static public Type system_array_type;
82         static public Type system_type_type;
83         static public Type system_assemblybuilder_type;
84         static public MethodInfo system_int_array_get_length;
85         static public MethodInfo system_int_array_get_rank;
86         static public MethodInfo system_object_array_clone;
87         static public MethodInfo system_int_array_get_length_int;
88         static public MethodInfo system_int_array_get_lower_bound_int;
89         static public MethodInfo system_int_array_get_upper_bound_int;
90         static public MethodInfo system_void_array_copyto_array_int;
91         static public MethodInfo system_void_set_corlib_type_builders;
92
93         
94         //
95         // Internal, not really used outside
96         //
97         static Type runtime_helpers_type;
98         
99         //
100         // These methods are called by code generated by the compiler
101         //
102         static public MethodInfo string_concat_string_string;
103         static public MethodInfo string_concat_object_object;
104         static public MethodInfo string_isinterneted_string;
105         static public MethodInfo system_type_get_type_from_handle;
106         static public MethodInfo object_getcurrent_void;
107         static public MethodInfo bool_movenext_void;
108         static public MethodInfo void_dispose_void;
109         static public MethodInfo void_monitor_enter_object;
110         static public MethodInfo void_monitor_exit_object;
111         static public MethodInfo void_initializearray_array_fieldhandle;
112         static public MethodInfo int_getlength_int;
113         static public MethodInfo delegate_combine_delegate_delegate;
114         static public MethodInfo delegate_remove_delegate_delegate;
115         static public MethodInfo int_get_offset_to_string_data;
116         static public MethodInfo int_array_get_length;
117         static public MethodInfo int_array_get_rank;
118         static public MethodInfo object_array_clone;
119         static public MethodInfo int_array_get_length_int;
120         static public MethodInfo int_array_get_lower_bound_int;
121         static public MethodInfo int_array_get_upper_bound_int;
122         static public MethodInfo void_array_copyto_array_int;
123         
124         //
125         // The attribute constructors.
126         //
127         static public ConstructorInfo cons_param_array_attribute;
128         static public ConstructorInfo void_decimal_ctor_five_args;
129         static public ConstructorInfo unverifiable_code_ctor;
130         
131         // <remarks>
132         //   Holds the Array of Assemblies that have been loaded
133         //   (either because it is the default or the user used the
134         //   -r command line option)
135         // </remarks>
136         static Assembly [] assemblies;
137
138         // <remarks>
139         //  Keeps a list of module builders. We used this to do lookups
140         //  on the modulebuilder using GetType -- needed for arrays
141         // </remarks>
142         static ModuleBuilder [] modules;
143
144         // <remarks>
145         //   This is the type_cache from the assemblies to avoid
146         //   hitting System.Reflection on every lookup.
147         // </summary>
148         static Hashtable types;
149
150         // <remarks>
151         //  This is used to hotld the corresponding TypeContainer objects
152         //  since we need this in FindMembers
153         // </remarks>
154         static Hashtable typecontainers;
155
156         // <remarks>
157         //   Keeps track of those types that are defined by the
158         //   user's program
159         // </remarks>
160         static ArrayList user_types;
161
162         // <remarks>
163         //   Keeps a mapping between TypeBuilders and their TypeContainers
164         // </remarks>
165         static PtrHashtable builder_to_container;
166
167         // <remarks>
168         //   Tracks the interfaces implemented by typebuilders.  We only
169         //   enter those who do implement or or more interfaces
170         // </remarks>
171         static PtrHashtable builder_to_ifaces;
172
173         // <remarks>
174         //   Maps MethodBase.RuntimeTypeHandle to a Type array that contains
175         //   the arguments to the method
176         // </remarks>
177         static Hashtable method_arguments;
178
179         // <remarks>
180         //   Maybe `method_arguments' should be replaced and only
181         //   method_internal_params should be kept?
182         // <remarks>
183         static Hashtable method_internal_params;
184
185         static PtrHashtable builder_to_interface;
186
187         // <remarks>
188         //  Keeps track of delegate types
189         // </remarks>
190
191         static Hashtable builder_to_delegate;
192
193         // <remarks>
194         //  Keeps track of enum types
195         // </remarks>
196
197         static Hashtable builder_to_enum;
198
199         // <remarks>
200         //  Keeps track of attribute types
201         // </remarks>
202
203         static Hashtable builder_to_attr;
204
205         struct Signature {
206                 public string name;
207                 public Type [] args;
208         }
209
210         /// <summary>
211         ///   A filter for Findmembers that uses the Signature object to
212         ///   extract objects
213         /// </summary>
214         static bool SignatureFilter (MemberInfo mi, object criteria)
215         {
216                 Signature sig = (Signature) criteria;
217
218                 if (!(mi is MethodBase))
219                         return false;
220                 
221                 if (mi.Name != sig.name)
222                         return false;
223
224                 int count = sig.args.Length;
225                 
226                 if (mi is MethodBuilder || mi is ConstructorBuilder){
227                         Type [] candidate_args = GetArgumentTypes ((MethodBase) mi);
228
229                         if (candidate_args.Length != count)
230                                 return false;
231                         
232                         for (int i = 0; i < count; i++)
233                                 if (candidate_args [i] != sig.args [i])
234                                         return false;
235                         
236                         return true;
237                 } else {
238                         ParameterInfo [] pars = ((MethodBase) mi).GetParameters ();
239
240                         if (pars.Length != count)
241                                 return false;
242
243                         for (int i = 0; i < count; i++)
244                                 if (pars [i].ParameterType != sig.args [i])
245                                         return false;
246                         return true;
247                 }
248         }
249
250         // A delegate that points to the filter above.
251         static MemberFilter signature_filter;
252
253         static TypeManager ()
254         {
255                 assemblies = new Assembly [0];
256                 modules = null;
257                 user_types = new ArrayList ();
258                 
259                 types = new Hashtable ();
260                 typecontainers = new Hashtable ();
261                 
262                 builder_to_interface = new PtrHashtable ();
263                 builder_to_delegate = new PtrHashtable ();
264                 builder_to_enum  = new PtrHashtable ();
265                 builder_to_attr = new PtrHashtable ();
266                 method_arguments = new PtrHashtable ();
267                 method_internal_params = new PtrHashtable ();
268                 builder_to_container = new PtrHashtable ();
269                 builder_to_ifaces = new PtrHashtable ();
270                 
271                 NoTypes = new Type [0];
272
273                 signature_filter = new MemberFilter (SignatureFilter);
274         }
275
276         public static void AddUserType (string name, TypeBuilder t, Type [] ifaces)
277         {
278                 try {
279                         types.Add (name, t);
280                 } catch {
281                         Type prev = (Type) types [name];
282                         TypeContainer tc = (TypeContainer) builder_to_container [prev];
283
284                         if (tc != null){
285                                 //
286                                 // This probably never happens, as we catch this before
287                                 //
288                                 Report.Error (-17, "The type `" + name + "' has already been defined.");
289                                 return;
290                         }
291
292                         tc = (TypeContainer) builder_to_container [t];
293                         
294                         Report.Warning (
295                                 1595, "The type `" + name + "' is defined in an existing assembly;"+
296                                 " Using the new definition from: " + tc.Location);
297                         Report.Warning (1595, "Previously defined in: " + prev.Assembly.FullName);
298                         
299                         types.Remove (name);
300                         types.Add (name, t);
301                 }
302                 user_types.Add (t);
303                         
304                 if (ifaces != null)
305                         builder_to_ifaces [t] = ifaces;
306         }
307
308         //
309         // This entry point is used by types that we define under the covers
310         // 
311         public static void RegisterBuilder (TypeBuilder tb, Type [] ifaces)
312         {
313                 if (ifaces != null)
314                         builder_to_ifaces [tb] = ifaces;
315         }
316         
317         public static void AddUserType (string name, TypeBuilder t, TypeContainer tc, Type [] ifaces)
318         {
319                 builder_to_container.Add (t, tc);
320                 typecontainers.Add (name, tc);
321                 AddUserType (name, t, ifaces);
322         }
323
324         public static void AddDelegateType (string name, TypeBuilder t, Delegate del)
325         {
326                 types.Add (name, t);
327                 builder_to_delegate.Add (t, del);
328         }
329         
330         public static void AddEnumType (string name, TypeBuilder t, Enum en)
331         {
332                 types.Add (name, t);
333                 builder_to_enum.Add (t, en);
334         }
335
336         public static void AddUserInterface (string name, TypeBuilder t, Interface i, Type [] ifaces)
337         {
338                 AddUserType (name, t, ifaces);
339                 builder_to_interface.Add (t, i);
340         }
341
342         public static void RegisterAttrType (Type t, TypeContainer tc)
343         {
344                 builder_to_attr.Add (t, tc);
345         }
346                 
347         /// <summary>
348         ///   Returns the TypeContainer whose Type is `t' or null if there is no
349         ///   TypeContainer for `t' (ie, the Type comes from a library)
350         /// </summary>
351         public static TypeContainer LookupTypeContainer (Type t)
352         {
353                 return (TypeContainer) builder_to_container [t];
354         }
355
356         public static Interface LookupInterface (Type t)
357         {
358                 return (Interface) builder_to_interface [t];
359         }
360
361         public static Delegate LookupDelegate (Type t)
362         {
363                 return (Delegate) builder_to_delegate [t];
364         }
365
366         public static Enum LookupEnum (Type t)
367         {
368                 return (Enum) builder_to_enum [t];
369         }
370         
371         public static TypeContainer LookupAttr (Type t)
372         {
373                 return (TypeContainer) builder_to_attr [t];
374         }
375         
376         /// <summary>
377         ///   Registers an assembly to load types from.
378         /// </summary>
379         public static void AddAssembly (Assembly a)
380         {
381                 int top = assemblies.Length;
382                 Assembly [] n = new Assembly [top + 1];
383
384                 assemblies.CopyTo (n, 0);
385                 
386                 n [top] = a;
387                 assemblies = n;
388         }
389
390         /// <summary>
391         ///  Registers a module builder to lookup types from
392         /// </summary>
393         public static void AddModule (ModuleBuilder mb)
394         {
395                 int top = modules != null ? modules.Length : 0;
396                 ModuleBuilder [] n = new ModuleBuilder [top + 1];
397
398                 if (modules != null)
399                         modules.CopyTo (n, 0);
400                 n [top] = mb;
401                 modules = n;
402         }
403
404         /// <summary>
405         ///   Returns the Type associated with @name
406         /// </summary>
407         public static Type LookupType (string name)
408         {
409                 Type t;
410
411                 //
412                 // First lookup in user defined and cached values
413                 //
414
415                 t = (Type) types [name];
416                 if (t != null)
417                         return t;
418
419                 foreach (Assembly a in assemblies){
420                         t = a.GetType (name);
421                         if (t != null){
422                                 types [name] = t;
423
424                                 return t;
425                         }
426                 }
427
428                 foreach (ModuleBuilder mb in modules) {
429                         t = mb.GetType (name);
430                         if (t != null) {
431                                 types [name] = t;
432                                 return t;
433                         }
434                 }
435                 
436                 return null;
437         }
438
439         /// <summary>
440         ///   Returns the C# name of a type if possible, or the full type name otherwise
441         /// </summary>
442         static public string CSharpName (Type t)
443         {
444                 return Regex.Replace (t.FullName, 
445                         @"^System\." +
446                         @"(Int32|UInt32|Int16|Uint16|Int64|UInt64|" +
447                         @"Single|Double|Char|Decimal|Byte|SByte|Object|" +
448                         @"Boolean|String|Void)" +
449                         @"(\W+|\b)", 
450                         new MatchEvaluator (CSharpNameMatch));
451         }       
452         
453         static String CSharpNameMatch (Match match) 
454         {
455                 string s = match.Groups [1].Captures [0].Value;
456                 return s.ToLower ().
457                 Replace ("int32", "int").
458                 Replace ("uint32", "uint").
459                 Replace ("int16", "short").
460                 Replace ("uint16", "ushort").
461                 Replace ("int64", "long").
462                 Replace ("uint64", "ulong").
463                 Replace ("single", "float").
464                 Replace ("boolean", "bool")
465                 + match.Groups [2].Captures [0].Value;
466         }
467
468         /// <summary>
469         ///   Returns the signature of the method
470         /// </summary>
471         static public string CSharpSignature (MethodBase mb)
472         {
473                 string sig = "(";
474
475                 //
476                 // FIXME: We should really have a single function to do
477                 // everything instead of the following 5 line pattern
478                 //
479                 ParameterData iparams = LookupParametersByBuilder (mb);
480
481                 if (iparams == null){
482                         ParameterInfo [] pi = mb.GetParameters ();
483                         iparams = new ReflectionParameters (pi);
484                 }
485                 
486                 for (int i = 0; i < iparams.Count; i++) {
487                         if (i > 0) {
488                                 sig += ", ";
489                         }
490                         sig += iparams.ParameterDesc(i);
491                 }
492                 sig += ")";
493
494                 return mb.DeclaringType.Name + "." + mb.Name + sig;
495         }
496
497         /// <summary>
498         ///   Looks up a type, and aborts if it is not found.  This is used
499         ///   by types required by the compiler
500         /// </summary>
501         static Type CoreLookupType (string name)
502         {
503                 Type t = LookupType (name);
504
505                 if (t == null){
506                         Report.Error (518, "The predefined type `" + name + "' is not defined or imported");
507                         Environment.Exit (0);
508                 }
509
510                 return t;
511         }
512
513         /// <summary>
514         ///   Returns the MethodInfo for a method named `name' defined
515         ///   in type `t' which takes arguments of types `args'
516         /// </summary>
517         static MethodInfo GetMethod (Type t, string name, Type [] args)
518         {
519                 MemberInfo [] mi;
520                 Signature sig;
521
522                 sig.name = name;
523                 sig.args = args;
524                 
525                 mi = FindMembers (
526                         t, MemberTypes.Method,
527                         instance_and_static | BindingFlags.Public, signature_filter, sig);
528                 if (mi == null || mi.Length == 0 || !(mi [0] is MethodInfo)){
529                         Report.Error (-19, "Can not find the core function `" + name + "'");
530                         return null;
531                 }
532
533                 return (MethodInfo) mi [0];
534         }
535
536         /// <summary>
537         ///    Returns the ConstructorInfo for "args"
538         /// </summary>
539         static ConstructorInfo GetConstructor (Type t, Type [] args)
540         {
541                 MemberInfo [] mi;
542                 Signature sig;
543
544                 sig.name = ".ctor";
545                 sig.args = args;
546                 
547                 mi = FindMembers (t, MemberTypes.Constructor,
548                                   instance_and_static | BindingFlags.Public | BindingFlags.DeclaredOnly, signature_filter, sig);
549                 if (mi == null || mi.Length == 0 || !(mi [0] is ConstructorInfo)){
550                         Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
551                         return null;
552                 }
553
554                 return (ConstructorInfo) mi [0];
555         }
556
557         public static void InitEnumUnderlyingTypes ()
558         {
559
560                 int32_type    = CoreLookupType ("System.Int32");
561                 int64_type    = CoreLookupType ("System.Int64");
562                 uint32_type   = CoreLookupType ("System.UInt32"); 
563                 uint64_type   = CoreLookupType ("System.UInt64"); 
564                 byte_type     = CoreLookupType ("System.Byte");
565                 sbyte_type    = CoreLookupType ("System.SByte");
566                 short_type    = CoreLookupType ("System.Int16");
567                 ushort_type   = CoreLookupType ("System.UInt16");
568         }
569         
570         /// <remarks>
571         ///   The types have to be initialized after the initial
572         ///   population of the type has happened (for example, to
573         ///   bootstrap the corlib.dll
574         /// </remarks>
575         public static void InitCoreTypes ()
576         {
577                 object_type   = CoreLookupType ("System.Object");
578                 value_type    = CoreLookupType ("System.ValueType");
579
580                 InitEnumUnderlyingTypes ();
581
582                 char_type     = CoreLookupType ("System.Char");
583                 string_type   = CoreLookupType ("System.String");
584                 float_type    = CoreLookupType ("System.Single");
585                 double_type   = CoreLookupType ("System.Double");
586                 char_ptr_type = CoreLookupType ("System.Char*");
587                 decimal_type  = CoreLookupType ("System.Decimal");
588                 bool_type     = CoreLookupType ("System.Boolean");
589                 enum_type     = CoreLookupType ("System.Enum");
590
591                 multicast_delegate_type = CoreLookupType ("System.MulticastDelegate");
592                 delegate_type           = CoreLookupType ("System.Delegate");
593
594                 array_type    = CoreLookupType ("System.Array");
595                 void_type     = CoreLookupType ("System.Void");
596                 type_type     = CoreLookupType ("System.Type");
597
598                 runtime_field_handle_type = CoreLookupType ("System.RuntimeFieldHandle");
599                 runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices.RuntimeHelpers");
600                 default_member_type  = CoreLookupType ("System.Reflection.DefaultMemberAttribute");
601                 runtime_handle_type  = CoreLookupType ("System.RuntimeTypeHandle");
602                 asynccallback_type   = CoreLookupType ("System.AsyncCallback");
603                 iasyncresult_type    = CoreLookupType ("System.IAsyncResult");
604                 ienumerator_type     = CoreLookupType ("System.Collections.IEnumerator");
605                 idisposable_type     = CoreLookupType ("System.IDisposable");
606                 icloneable_type      = CoreLookupType ("System.ICloneable");
607                 monitor_type         = CoreLookupType ("System.Threading.Monitor");
608                 intptr_type          = CoreLookupType ("System.IntPtr");
609
610                 attribute_type       = CoreLookupType ("System.Attribute");
611                 attribute_usage_type = CoreLookupType ("System.AttributeUsageAttribute");
612                 dllimport_type       = CoreLookupType ("System.Runtime.InteropServices.DllImportAttribute");
613                 methodimpl_attr_type = CoreLookupType ("System.Runtime.CompilerServices.MethodImplAttribute");
614                 marshal_as_attr_type  = CoreLookupType ("System.Runtime.InteropServices.MarshalAsAttribute");
615                 param_array_type      = CoreLookupType ("System.ParamArrayAttribute");
616
617                 unverifiable_code_type= CoreLookupType ("System.Security.UnverifiableCodeAttribute");
618
619                 void_ptr_type         = CoreLookupType ("System.Void*");
620
621                 indexer_name_type     = CoreLookupType ("System.Runtime.CompilerServices.IndexerNameAttribute");
622
623                 //
624                 // Attribute types
625                 //
626                 obsolete_attribute_type = CoreLookupType ("System.ObsoleteAttribute");
627                 conditional_attribute_type = CoreLookupType ("System.Diagnostics.ConditionalAttribute");
628
629                 //
630                 // When compiling corlib, store the "real" types here.
631                 //
632                 if (!RootContext.StdLib) {
633                         system_int32_type = typeof (System.Int32);
634                         system_array_type = typeof (System.Array);
635                         system_type_type = typeof (System.Type);
636                         system_assemblybuilder_type = typeof (System.Reflection.Emit.AssemblyBuilder);
637
638                         Type [] void_arg = {  };
639                         system_int_array_get_length = GetMethod (
640                                 system_array_type, "get_Length", void_arg);
641                         system_int_array_get_rank = GetMethod (
642                                 system_array_type, "get_Rank", void_arg);
643                         system_object_array_clone = GetMethod (
644                                 system_array_type, "Clone", void_arg);
645
646                         Type [] system_int_arg = { system_int32_type };
647                         system_int_array_get_length_int = GetMethod (
648                                 system_array_type, "GetLength", system_int_arg);
649                         system_int_array_get_upper_bound_int = GetMethod (
650                                 system_array_type, "GetUpperBound", system_int_arg);
651                         system_int_array_get_lower_bound_int = GetMethod (
652                                 system_array_type, "GetLowerBound", system_int_arg);
653
654                         Type [] system_array_int_arg = { system_array_type, system_int32_type };
655                         system_void_array_copyto_array_int = GetMethod (
656                                 system_array_type, "CopyTo", system_array_int_arg);
657
658                         Type [] system_type_type_arg = { system_type_type, system_type_type, system_type_type };
659                         system_void_set_corlib_type_builders = GetMethod (
660                                 system_assemblybuilder_type, "SetCorlibTypeBuilders",
661                                 system_type_type_arg);
662
663                         object[] args = new object [3];
664                         args [0] = object_type;
665                         args [1] = value_type;
666                         args [2] = enum_type;
667
668                         system_void_set_corlib_type_builders.Invoke (CodeGen.AssemblyBuilder, args);
669                 }
670         }
671
672         //
673         // The helper methods that are used by the compiler
674         //
675         public static void InitCodeHelpers ()
676         {
677                 //
678                 // Now load the default methods that we use.
679                 //
680                 Type [] string_string = { string_type, string_type };
681                 string_concat_string_string = GetMethod (
682                         string_type, "Concat", string_string);
683
684                 Type [] object_object = { object_type, object_type };
685                 string_concat_object_object = GetMethod (
686                         string_type, "Concat", object_object);
687
688                 Type [] string_ = { string_type };
689                 string_isinterneted_string = GetMethod (
690                         string_type, "IsInterned", string_);
691                 
692                 Type [] runtime_type_handle = { runtime_handle_type };
693                 system_type_get_type_from_handle = GetMethod (
694                         type_type, "GetTypeFromHandle", runtime_type_handle);
695
696                 Type [] delegate_delegate = { delegate_type, delegate_type };
697                 delegate_combine_delegate_delegate = GetMethod (
698                                 delegate_type, "Combine", delegate_delegate);
699
700                 delegate_remove_delegate_delegate = GetMethod (
701                                 delegate_type, "Remove", delegate_delegate);
702
703                 //
704                 // Void arguments
705                 //
706                 Type [] void_arg = {  };
707                 object_getcurrent_void = GetMethod (
708                         ienumerator_type, "get_Current", void_arg);
709                 bool_movenext_void = GetMethod (
710                         ienumerator_type, "MoveNext", void_arg);
711                 void_dispose_void = GetMethod (
712                         idisposable_type, "Dispose", void_arg);
713                 int_get_offset_to_string_data = GetMethod (
714                         runtime_helpers_type, "get_OffsetToStringData", void_arg);
715                 int_array_get_length = GetMethod (
716                         array_type, "get_Length", void_arg);
717                 int_array_get_rank = GetMethod (
718                         array_type, "get_Rank", void_arg);
719
720                 //
721                 // Int32 arguments
722                 //
723                 Type [] int_arg = { int32_type };
724                 int_array_get_length_int = GetMethod (
725                         array_type, "GetLength", int_arg);
726                 int_array_get_upper_bound_int = GetMethod (
727                         array_type, "GetUpperBound", int_arg);
728                 int_array_get_lower_bound_int = GetMethod (
729                         array_type, "GetLowerBound", int_arg);
730
731                 //
732                 // System.Array methods
733                 //
734                 object_array_clone = GetMethod (
735                         array_type, "Clone", void_arg);
736                 Type [] array_int_arg = { array_type, int32_type };
737                 void_array_copyto_array_int = GetMethod (
738                         array_type, "CopyTo", array_int_arg);
739                 
740                 //
741                 // object arguments
742                 //
743                 Type [] object_arg = { object_type };
744                 void_monitor_enter_object = GetMethod (
745                         monitor_type, "Enter", object_arg);
746                 void_monitor_exit_object = GetMethod (
747                         monitor_type, "Exit", object_arg);
748
749                 Type [] array_field_handle_arg = { array_type, runtime_field_handle_type };
750                 
751                 void_initializearray_array_fieldhandle = GetMethod (
752                         runtime_helpers_type, "InitializeArray", array_field_handle_arg);
753
754                 //
755                 // Array functions
756                 //
757                 int_getlength_int = GetMethod (
758                         array_type, "GetLength", int_arg);
759
760                 //
761                 // Decimal constructors
762                 //
763                 Type [] dec_arg = { int32_type, int32_type, int32_type, bool_type, byte_type };
764                 void_decimal_ctor_five_args = GetConstructor (
765                         decimal_type, dec_arg);
766                 
767                 //
768                 // Attributes
769                 //
770                 cons_param_array_attribute = GetConstructor (
771                         param_array_type, void_arg);
772
773                 unverifiable_code_ctor = GetConstructor (
774                         unverifiable_code_type, void_arg);
775                 
776         }
777
778         const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance;
779
780         //
781         // FIXME: This can be optimized easily.  speedup by having a single builder mapping
782         //
783         public static MemberInfo [] FindMembers (Type t, MemberTypes mt, BindingFlags bf,
784                                                  MemberFilter filter, object criteria)
785         {
786                 //
787                 // We have to take care of arrays specially, because GetType on
788                 // a TypeBuilder array will return a Type, not a TypeBuilder,
789                 // and we can not call FindMembers on this type.
790                 //
791                 if (t.IsSubclassOf (TypeManager.array_type))
792                         return TypeManager.array_type.FindMembers (mt, bf, filter, criteria);
793                 
794                 if (!(t is TypeBuilder)){
795                         //
796                         // Since FindMembers will not lookup both static and instance
797                         // members, we emulate this behaviour here.
798                         //
799                         if ((bf & instance_and_static) == instance_and_static){
800                                 MemberInfo [] i_members = t.FindMembers (
801                                         mt, bf & ~BindingFlags.Static, filter, criteria);
802
803                                 int i_len = i_members.Length;
804                                 if (i_len == 1){
805                                         MemberInfo one = i_members [0];
806
807                                         //
808                                         // If any of these are present, we are done!
809                                         //
810                                         if ((one is Type) || (one is EventInfo) || (one is FieldInfo))
811                                                 return i_members;
812                                 }
813                                 
814                                 MemberInfo [] s_members = t.FindMembers (
815                                         mt, bf & ~BindingFlags.Instance, filter, criteria);
816
817                                 int s_len = s_members.Length;
818                                 if (i_len > 0 || s_len > 0){
819                                         MemberInfo [] both = new MemberInfo [i_len + s_len];
820
821                                         i_members.CopyTo (both, 0);
822                                         s_members.CopyTo (both, i_len);
823
824                                         return both;
825                                 } else {
826                                         if (i_len > 0)
827                                                 return i_members;
828                                         else
829                                                 return s_members;
830                                 }
831                         }
832                         return t.FindMembers (mt, bf, filter, criteria);
833                 }
834
835                 //
836                 // FIXME: We should not have builder_to_blah everywhere,
837                 // we should just have a builder_to_findmemberizable
838                 // and have them implement a new ICanFindMembers interface
839                 //
840                 Enum e = (Enum) builder_to_enum [t];
841
842                 if (e != null)
843                         return e.FindMembers (mt, bf, filter, criteria);
844                 
845                 Delegate del = (Delegate) builder_to_delegate [t];
846
847                 if (del != null)
848                         return del.FindMembers (mt, bf, filter, criteria);
849
850                 Interface iface = (Interface) builder_to_interface [t];
851
852                 if (iface != null) 
853                         return iface.FindMembers (mt, bf, filter, criteria);
854                 
855                 TypeContainer tc = (TypeContainer) builder_to_container [t];
856
857                 if (tc != null)
858                         return tc.FindMembers (mt, bf, filter, criteria);
859
860                 return null;
861         }
862
863         public static bool IsBuiltinType (Type t)
864         {
865                 if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
866                     t == int64_type || t == uint64_type || t == float_type || t == double_type ||
867                     t == char_type || t == short_type || t == decimal_type || t == bool_type ||
868                     t == sbyte_type || t == byte_type || t == ushort_type)
869                         return true;
870                 else
871                         return false;
872         }
873
874         public static bool IsDelegateType (Type t)
875         {
876                 if (t.IsSubclassOf (TypeManager.delegate_type))
877                         return true;
878                 else
879                         return false;
880         }
881         
882         public static bool IsEnumType (Type t)
883         {
884                 if (t.IsSubclassOf (TypeManager.enum_type))
885                         return true;
886                 else
887                         return false;
888         }
889         
890         public static bool IsInterfaceType (Type t)
891         {
892                 Interface iface = (Interface) builder_to_interface [t];
893
894                 if (iface != null)
895                         return true;
896                 else
897                         return false;
898         }
899
900         /// <summary>
901         ///   Returns the User Defined Types
902         /// </summary>
903         public static ArrayList UserTypes {
904                 get {
905                         return user_types;
906                 }
907         }
908
909         public static Hashtable TypeContainers {
910                 get {
911                         return typecontainers;
912                 }
913         }
914
915         static Hashtable builder_to_constant;
916
917         public static void RegisterConstant (FieldBuilder fb, Const c)
918         {
919                 if (builder_to_constant == null)
920                         builder_to_constant = new PtrHashtable ();
921
922                 if (builder_to_constant.Contains (fb))
923                         return;
924
925                 builder_to_constant.Add (fb, c);
926         }
927
928         public static Const LookupConstant (FieldBuilder fb)
929         {
930                 if (builder_to_constant == null)
931                         return null;
932                 
933                 return (Const) builder_to_constant [fb];
934         }
935         
936         /// <summary>
937         ///   Gigantic work around for missing features in System.Reflection.Emit follows.
938         /// </summary>
939         ///
940         /// <remarks>
941         ///   Since System.Reflection.Emit can not return MethodBase.GetParameters
942         ///   for anything which is dynamic, and we need this in a number of places,
943         ///   we register this information here, and use it afterwards.
944         /// </remarks>
945         static public bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] args)
946         {
947                 if (args == null)
948                         args = NoTypes;
949                                 
950                 method_arguments.Add (mb, args);
951                 method_internal_params.Add (mb, ip);
952                 
953                 return true;
954         }
955         
956         static public InternalParameters LookupParametersByBuilder (MethodBase mb)
957         {
958                 if (! (mb is ConstructorBuilder || mb is MethodBuilder))
959                         return null;
960                 
961                 if (method_internal_params.Contains (mb))
962                         return (InternalParameters) method_internal_params [mb];
963                 else
964                         throw new Exception ("Argument for Method not registered" + mb);
965         }
966
967         /// <summary>
968         ///    Returns the argument types for a method based on its methodbase
969         ///
970         ///    For dynamic methods, we use the compiler provided types, for
971         ///    methods from existing assemblies we load them from GetParameters,
972         ///    and insert them into the cache
973         /// </summary>
974         static public Type [] GetArgumentTypes (MethodBase mb)
975         {
976                 if (method_arguments.Contains (mb))
977                         return (Type []) method_arguments [mb];
978                 else {
979                         ParameterInfo [] pi = mb.GetParameters ();
980                         int c = pi.Length;
981                         Type [] types = new Type [c];
982                         
983                         for (int i = 0; i < c; i++)
984                                 types [i] = pi [i].ParameterType;
985
986                         method_arguments.Add (mb, types);
987                         return types;
988                 }
989         }
990         
991         // <remarks>
992         //  This is a workaround the fact that GetValue is not
993         //  supported for dynamic types
994         // </remarks>
995         static Hashtable fields = new Hashtable ();
996         static public bool RegisterFieldValue (FieldBuilder fb, object value)
997         {
998                 if (fields.Contains (fb))
999                         return false;
1000
1001                 fields.Add (fb, value);
1002
1003                 return true;
1004         }
1005
1006         static public object GetValue (FieldBuilder fb)
1007         {
1008                 return fields [fb];
1009         }
1010
1011         static Hashtable fieldbuilders_to_fields = new Hashtable ();
1012         static public bool RegisterFieldBase (FieldBuilder fb, FieldBase f)
1013         {
1014                 if (fieldbuilders_to_fields.Contains (fb))
1015                         return false;
1016
1017                 fieldbuilders_to_fields.Add (fb, f);
1018                 return true;
1019         }
1020
1021         static public FieldBase GetField (FieldInfo fb)
1022         {
1023                 return (FieldBase) fieldbuilders_to_fields [fb];
1024         }
1025         
1026         static Hashtable events;
1027
1028         static public bool RegisterEvent (MyEventBuilder eb, MethodBase add, MethodBase remove)
1029         {
1030                 if (events == null)
1031                         events = new Hashtable ();
1032
1033                 if (events.Contains (eb))
1034                         return false;
1035
1036                 events.Add (eb, new Pair (add, remove));
1037
1038                 return true;
1039         }
1040
1041         static public MethodInfo GetAddMethod (EventInfo ei)
1042         {
1043                 if (ei is MyEventBuilder) {
1044                         Pair pair = (Pair) events [ei];
1045
1046                         return (MethodInfo) pair.First;
1047                 } else
1048                         return ei.GetAddMethod ();
1049         }
1050
1051         static public MethodInfo GetRemoveMethod (EventInfo ei)
1052         {
1053                 if (ei is MyEventBuilder) {
1054                         Pair pair = (Pair) events [ei];
1055
1056                         return (MethodInfo) pair.Second;
1057                 } else
1058                         return ei.GetAddMethod ();
1059         }
1060
1061         static Hashtable priv_fields_events;
1062
1063         static public bool RegisterPrivateFieldOfEvent (EventInfo einfo, FieldBuilder builder)
1064         {
1065                 if (priv_fields_events == null)
1066                         priv_fields_events = new Hashtable ();
1067
1068                 if (priv_fields_events.Contains (einfo))
1069                         return false;
1070
1071                 priv_fields_events.Add (einfo, builder);
1072
1073                 return true;
1074         }
1075
1076         static public MemberInfo GetPrivateFieldOfEvent (EventInfo ei)
1077         {
1078                 return (MemberInfo) priv_fields_events [ei];
1079         }
1080         
1081         static Hashtable properties;
1082         
1083         static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set)
1084         {
1085                 if (properties == null)
1086                         properties = new Hashtable ();
1087
1088                 if (properties.Contains (pb))
1089                         return false;
1090
1091                 properties.Add (pb, new Pair (get, set));
1092
1093                 return true;
1094         }
1095         
1096         //
1097         // FIXME: we need to return the accessors depending on whether
1098         // they are visible or not.
1099         //
1100         static public MethodInfo [] GetAccessors (PropertyInfo pi)
1101         {
1102                 MethodInfo [] ret;
1103
1104                 if (pi is PropertyBuilder){
1105                         Pair pair = (Pair) properties [pi];
1106
1107                         ret = new MethodInfo [2];
1108                         ret [0] = (MethodInfo) pair.First;
1109                         ret [1] = (MethodInfo) pair.Second;
1110
1111                         return ret;
1112                 } else {
1113                         MethodInfo [] mi = new MethodInfo [2];
1114
1115                         //
1116                         // Why this and not pi.GetAccessors?
1117                         // Because sometimes index 0 is the getter
1118                         // sometimes it is 1
1119                         //
1120                         mi [0] = pi.GetGetMethod (true);
1121                         mi [1] = pi.GetSetMethod (true);
1122
1123                         return mi;
1124                 }
1125         }
1126
1127         static public MethodInfo GetPropertyGetter (PropertyInfo pi)
1128         {
1129                 if (pi is PropertyBuilder){
1130                         Pair de = (Pair) properties [pi];
1131
1132                         return (MethodInfo) de.Second;
1133                 } else
1134                         return pi.GetSetMethod ();
1135         }
1136
1137         static public MethodInfo GetPropertySetter (PropertyInfo pi)
1138         {
1139                 if (pi is PropertyBuilder){
1140                         Pair de = (Pair) properties [pi];
1141
1142                         return (MethodInfo) de.First;
1143                 } else
1144                         return pi.GetGetMethod ();
1145         }
1146
1147         /// <summary>
1148         ///   Given an array of interface types, expand and eliminate repeated ocurrences
1149         ///   of an interface.  
1150         /// </summary>
1151         ///
1152         /// <remarks>
1153         ///   This expands in context like: IA; IB : IA; IC : IA, IB; the interface "IC" to
1154         ///   be IA, IB, IC.
1155         /// </remarks>
1156         public static Type [] ExpandInterfaces (Type [] base_interfaces)
1157         {
1158                 ArrayList new_ifaces = new ArrayList ();
1159                 
1160                 foreach (Type iface in base_interfaces){
1161                         if (!new_ifaces.Contains (iface))
1162                                 new_ifaces.Add (iface);
1163                         
1164                         Type [] implementing = TypeManager.GetInterfaces (iface);
1165                         
1166                         foreach (Type imp in implementing){
1167                                 if (!new_ifaces.Contains (imp))
1168                                         new_ifaces.Add (imp);
1169                         }
1170                 }
1171                 Type [] ret = new Type [new_ifaces.Count];
1172                 new_ifaces.CopyTo (ret, 0);
1173                 return ret;
1174         }
1175                 
1176         /// <summary>
1177         ///   This function returns the interfaces in the type `t'.  Works with
1178         ///   both types and TypeBuilders.
1179         /// </summary>
1180         public static Type [] GetInterfaces (Type t)
1181         {
1182                 //
1183                 // The reason for catching the Array case is that Reflection.Emit
1184                 // will not return a TypeBuilder for Array types of TypeBuilder types,
1185                 // but will still throw an exception if we try to call GetInterfaces
1186                 // on the type.
1187                 //
1188                 // Since the array interfaces are always constant, we return those for
1189                 // the System.Array
1190                 //
1191                 
1192                 if (t.IsArray)
1193                         t = TypeManager.array_type;
1194                 
1195                 if (t is TypeBuilder){
1196                         Type [] parent_ifaces;
1197                         
1198                         if (t.BaseType == null)
1199                                 parent_ifaces = NoTypes;
1200                         else
1201                                 parent_ifaces = GetInterfaces (t.BaseType);
1202                         Type [] type_ifaces = (Type []) builder_to_ifaces [t];
1203                         if (type_ifaces == null)
1204                                 type_ifaces = NoTypes;
1205
1206                         int parent_count = parent_ifaces.Length;
1207                         Type [] result = new Type [parent_count + type_ifaces.Length];
1208                         parent_ifaces.CopyTo (result, 0);
1209                         type_ifaces.CopyTo (result, parent_count);
1210
1211                         return result;
1212                 } else
1213                         return t.GetInterfaces ();
1214         }
1215         
1216         /// <remarks>
1217         ///  The following is used to check if a given type implements an interface.
1218         ///  The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
1219         /// </remarks>
1220         public static bool ImplementsInterface (Type t, Type iface)
1221         {
1222                 Type [] interfaces;
1223
1224                 //
1225                 // FIXME OPTIMIZATION:
1226                 // as soon as we hit a non-TypeBuiler in the interface
1227                 // chain, we could return, as the `Type.GetInterfaces'
1228                 // will return all the interfaces implement by the type
1229                 // or its parents.
1230                 //
1231                 do {
1232                         interfaces = GetInterfaces (t);
1233
1234                         if (interfaces != null){
1235                                 foreach (Type i in interfaces){
1236                                         if (i == iface)
1237                                                 return true;
1238                                 }
1239                         }
1240                         
1241                         t = t.BaseType;
1242                 } while (t != null);
1243                 
1244                 return false;
1245         }
1246
1247         // This is a custom version of Convert.ChangeType() which works
1248         // with the TypeBuilder defined types when compiling corlib.
1249         public static object ChangeType (object value, Type conversionType)
1250         {
1251                 if (!(value is IConvertible))
1252                         throw new ArgumentException ();
1253
1254                 IConvertible convertValue = (IConvertible) value;
1255                 CultureInfo ci = CultureInfo.CurrentCulture;
1256                 NumberFormatInfo provider = ci.NumberFormat;
1257
1258                 //
1259                 // We must use Type.Equals() here since `conversionType' is
1260                 // the TypeBuilder created version of a system type and not
1261                 // the system type itself.  You cannot use Type.GetTypeCode()
1262                 // on such a type - it'd always return TypeCode.Object.
1263                 //
1264                 if (conversionType.Equals (typeof (Boolean)))
1265                         return (object)(convertValue.ToBoolean (provider));
1266                 else if (conversionType.Equals (typeof (Byte)))
1267                         return (object)(convertValue.ToByte (provider));
1268                 else if (conversionType.Equals (typeof (Char)))
1269                         return (object)(convertValue.ToChar (provider));
1270                 else if (conversionType.Equals (typeof (DateTime)))
1271                         return (object)(convertValue.ToDateTime (provider));
1272                 else if (conversionType.Equals (typeof (Decimal)))
1273                         return (object)(convertValue.ToDecimal (provider));
1274                 else if (conversionType.Equals (typeof (Double)))
1275                         return (object)(convertValue.ToDouble (provider));
1276                 else if (conversionType.Equals (typeof (Int16)))
1277                         return (object)(convertValue.ToInt16 (provider));
1278                 else if (conversionType.Equals (typeof (Int32)))
1279                         return (object)(convertValue.ToInt32 (provider));
1280                 else if (conversionType.Equals (typeof (Int64)))
1281                         return (object)(convertValue.ToInt64 (provider));
1282                 else if (conversionType.Equals (typeof (SByte)))
1283                         return (object)(convertValue.ToSByte (provider));
1284                 else if (conversionType.Equals (typeof (Single)))
1285                         return (object)(convertValue.ToSingle (provider));
1286                 else if (conversionType.Equals (typeof (String)))
1287                         return (object)(convertValue.ToString (provider));
1288                 else if (conversionType.Equals (typeof (UInt16)))
1289                         return (object)(convertValue.ToUInt16 (provider));
1290                 else if (conversionType.Equals (typeof (UInt32)))
1291                         return (object)(convertValue.ToUInt32 (provider));
1292                 else if (conversionType.Equals (typeof (UInt64)))
1293                         return (object)(convertValue.ToUInt64 (provider));
1294                 else if (conversionType.Equals (typeof (Object)))
1295                         return (object)(value);
1296                 else 
1297                         throw new InvalidCastException ();
1298         }
1299
1300         //
1301         // This is needed, because enumerations from assemblies
1302         // do not report their underlyingtype, but they report
1303         // themselves
1304         //
1305         public static Type EnumToUnderlying (Type t)
1306         {
1307                 if (t == TypeManager.enum_type)
1308                         return t;
1309
1310                 t = t.UnderlyingSystemType;
1311                 if (!TypeManager.IsEnumType (t))
1312                         return t;
1313         
1314                 if (t is TypeBuilder) {
1315                         // slow path needed to compile corlib
1316                         if (t == TypeManager.bool_type ||
1317                                         t == TypeManager.byte_type ||
1318                                         t == TypeManager.sbyte_type ||
1319                                         t == TypeManager.char_type ||
1320                                         t == TypeManager.short_type ||
1321                                         t == TypeManager.ushort_type ||
1322                                         t == TypeManager.int32_type ||
1323                                         t == TypeManager.uint32_type ||
1324                                         t == TypeManager.int64_type ||
1325                                         t == TypeManager.uint64_type)
1326                                 return t;
1327                         throw new Exception ("Unhandled typecode in enum " + " from " + t.AssemblyQualifiedName);
1328                 }
1329                 TypeCode tc = Type.GetTypeCode (t);
1330
1331                 switch (tc){
1332                 case TypeCode.Boolean:
1333                         return TypeManager.bool_type;
1334                 case TypeCode.Byte:
1335                         return TypeManager.byte_type;
1336                 case TypeCode.SByte:
1337                         return TypeManager.sbyte_type;
1338                 case TypeCode.Char:
1339                         return TypeManager.char_type;
1340                 case TypeCode.Int16:
1341                         return TypeManager.short_type;
1342                 case TypeCode.UInt16:
1343                         return TypeManager.ushort_type;
1344                 case TypeCode.Int32:
1345                         return TypeManager.int32_type;
1346                 case TypeCode.UInt32:
1347                         return TypeManager.uint32_type;
1348                 case TypeCode.Int64:
1349                         return TypeManager.int64_type;
1350                 case TypeCode.UInt64:
1351                         return TypeManager.uint64_type;
1352                 }
1353                 throw new Exception ("Unhandled typecode in enum " + tc + " from " + t.AssemblyQualifiedName);
1354         }
1355
1356         //
1357         // When compiling corlib and called with one of the core types, return
1358         // the corresponding typebuilder for that type.
1359         //
1360         public static Type TypeToCoreType (Type t)
1361         {
1362                 if (RootContext.StdLib || (t is TypeBuilder))
1363                         return t;
1364
1365                 TypeCode tc = Type.GetTypeCode (t);
1366
1367                 switch (tc){
1368                 case TypeCode.Boolean:
1369                         return TypeManager.bool_type;
1370                 case TypeCode.Byte:
1371                         return TypeManager.byte_type;
1372                 case TypeCode.SByte:
1373                         return TypeManager.sbyte_type;
1374                 case TypeCode.Char:
1375                         return TypeManager.char_type;
1376                 case TypeCode.Int16:
1377                         return TypeManager.short_type;
1378                 case TypeCode.UInt16:
1379                         return TypeManager.ushort_type;
1380                 case TypeCode.Int32:
1381                         return TypeManager.int32_type;
1382                 case TypeCode.UInt32:
1383                         return TypeManager.uint32_type;
1384                 case TypeCode.Int64:
1385                         return TypeManager.int64_type;
1386                 case TypeCode.UInt64:
1387                         return TypeManager.uint64_type;
1388                 case TypeCode.String:
1389                         return TypeManager.string_type;
1390                 default:
1391                         if (t == typeof (void))
1392                                 return TypeManager.void_type;
1393                         if (t == typeof (object))
1394                                 return TypeManager.object_type;
1395                         return t;
1396                 }
1397         }
1398
1399         /// <summary>
1400         ///   Utility function that can be used to probe whether a type
1401         ///   is managed or not.  
1402         /// </summary>
1403         public static bool VerifyUnManaged (Type t, Location loc)
1404         {
1405                 if (t.IsValueType || t.IsPointer){
1406                         //
1407                         // FIXME: this is more complex, we actually need to
1408                         // make sure that the type does not contain any
1409                         // classes itself
1410                         //
1411                         return true;
1412                 }
1413
1414                 if (!RootContext.StdLib && (t == TypeManager.decimal_type))
1415                         // We need this explicit check here to make it work when
1416                         // compiling corlib.
1417                         return true;
1418
1419                 Report.Error (
1420                         208, loc,
1421                         "Cannot take the address or size of a variable of a managed type ('" +
1422                         CSharpName (t) + "')");
1423                 return false;   
1424         }
1425         
1426         /// <summary>
1427         ///   Returns the name of the indexer in a given type.
1428         /// </summary>
1429         /// <remarks>
1430         ///   The default is not always `Item'.  The user can change this behaviour by
1431         ///   using the DefaultMemberAttribute in the class.
1432         ///
1433         ///   For example, the String class indexer is named `Chars' not `Item' 
1434         /// </remarks>
1435         public static string IndexerPropertyName (Type t)
1436         {
1437                 
1438                 if (t is TypeBuilder) {
1439                         TypeContainer tc = (TypeContainer) builder_to_container [t];
1440
1441                         //
1442                         // FIXME: Temporary hack, until we deploy the IndexerName
1443                         // property code (and attributes) in the interface code.
1444                         //
1445                         if (tc == null){
1446                                 return "Item";
1447                         }
1448                         
1449                         return tc.IndexerName;
1450                 }
1451                 
1452                 System.Attribute attr = System.Attribute.GetCustomAttribute (
1453                         t, TypeManager.default_member_type);
1454                 if (attr != null){
1455                         DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
1456                         return dma.MemberName;
1457                 }
1458
1459                 return "Item";
1460         }
1461
1462         public static void MakePinned (LocalBuilder builder)
1463         {
1464                 //
1465                 // FIXME: Flag the "LocalBuilder" type as being
1466                 // pinned.  Figure out API.
1467                 //
1468         }
1469
1470
1471         //
1472         // Returns whether the array of memberinfos contains the given method
1473         //
1474         static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method)
1475         {
1476                 Type [] new_args = TypeManager.GetArgumentTypes (new_method);
1477                 
1478                 foreach (MethodBase method in array){
1479                         if (method.Name != new_method.Name)
1480                                 continue;
1481                         
1482                         Type [] old_args = TypeManager.GetArgumentTypes (method);
1483                         int old_count = old_args.Length;
1484                         int i;
1485                         
1486                         if (new_args.Length != old_count)
1487                                 continue;
1488                         
1489                         for (i = 0; i < old_count; i++){
1490                                 if (old_args [i] != new_args [i])
1491                                         break;
1492                         }
1493                         if (i != old_count)
1494                                 continue;
1495                         
1496                         if (!(method is MethodInfo && new_method is MethodInfo))
1497                                 return true;
1498                         
1499                         if (((MethodInfo) method).ReturnType == ((MethodInfo) new_method).ReturnType)
1500                                 return true;
1501                 }
1502                 return false;
1503         }
1504         
1505         //
1506         // We copy methods from `new_members' into `target_list' if the signature
1507         // for the method from in the new list does not exist in the target_list
1508         //
1509         // The name is assumed to be the same.
1510         //
1511         public static ArrayList CopyNewMethods (ArrayList target_list, MemberInfo [] new_members)
1512         {
1513                 if (target_list == null){
1514                         target_list = new ArrayList ();
1515
1516                         foreach (MemberInfo mi in new_members){
1517                                 if (mi is MethodBase)
1518                                         target_list.Add (mi);
1519                         }
1520                         return target_list;
1521                 }
1522                 
1523                 MemberInfo [] target_array = new MemberInfo [target_list.Count];
1524                 target_list.CopyTo (target_array, 0);
1525                 
1526                 foreach (MemberInfo mi in new_members){
1527                         MethodBase new_method = (MethodBase) mi;
1528                         
1529                         if (!ArrayContainsMethod (target_array, new_method))
1530                                 target_list.Add (new_method);
1531                 }
1532                 return target_list;
1533         }
1534
1535         [Flags]
1536         public enum MethodFlags {
1537                 IsObsolete = 1,
1538                 ShouldIgnore = 2
1539         }
1540         
1541         static public MethodFlags GetMethodFlags (MethodBase mb)
1542         {
1543                 MethodFlags flags = 0;
1544                 
1545                 if (mb.DeclaringType is TypeBuilder){
1546                         //
1547                         // FIXME: Support lookups of Obsolete and ConditionalAttribute
1548                         // on MethodBuilders.   
1549                         //
1550                         return 0;
1551                 }
1552
1553                 object [] attrs = mb.GetCustomAttributes (false);
1554                 foreach (object ta in attrs){
1555                         if (!(ta is System.Attribute)){
1556                                 Console.WriteLine ("Unknown type in GetMethodFlags: " + ta);
1557                                 continue;
1558                         }
1559                         System.Attribute a = (System.Attribute) ta;
1560                         if (a.TypeId == TypeManager.obsolete_attribute_type){
1561                                 flags |= MethodFlags.IsObsolete;
1562                                 continue;
1563                         }
1564                         
1565                         //
1566                         // Skip over conditional code.
1567                         //
1568                         if (a.TypeId == TypeManager.conditional_attribute_type){
1569                                 ConditionalAttribute ca = (ConditionalAttribute) a;
1570
1571                                 if (RootContext.AllDefines [ca.ConditionString] == null)
1572                                         flags |= MethodFlags.ShouldIgnore;
1573                         }
1574                 }
1575
1576                 return flags;
1577         }
1578         
1579 #region MemberLookup implementation
1580         
1581         //
1582         // Name of the member
1583         //
1584         static string   closure_name;
1585
1586         //
1587         // Whether we allow private members in the result (since FindMembers
1588         // uses NonPublic for both protected and private), we need to distinguish.
1589         //
1590         static bool     closure_private_ok;
1591
1592         //
1593         // Who is invoking us and which type is being queried currently.
1594         //
1595         static Type     closure_invocation_type;
1596         static Type     closure_queried_type;
1597
1598         //
1599         // The assembly that defines the type is that is calling us
1600         //
1601         static Assembly closure_invocation_assembly;
1602
1603         //
1604         // This filter filters by name + whether it is ok to include private
1605         // members in the search
1606         //
1607         static internal bool FilterWithClosure (MemberInfo m, object filter_criteria)
1608         {
1609                 //
1610                 // Hack: we know that the filter criteria will always be in the `closure'
1611                 // fields. 
1612                 //
1613
1614                 if (m.Name != closure_name)
1615                         return false;
1616
1617                 //
1618                 // Ugly: we need to find out the type of `m', and depending
1619                 // on this, tell whether we accept or not
1620                 //
1621                 if (m is MethodBase){
1622                         MethodBase mb = (MethodBase) m;
1623                         MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
1624
1625                         if (ma == MethodAttributes.Private)
1626                                 return closure_private_ok;
1627
1628                         //
1629                         // FamAndAssem requires that we not only derivate, but we are on the
1630                         // same assembly.  
1631                         //
1632                         if (ma == MethodAttributes.FamANDAssem){
1633                                 if (closure_invocation_assembly != mb.DeclaringType.Assembly)
1634                                         return false;
1635                         }
1636
1637                         // FamORAssem, Family and Public:
1638                         return true;
1639                 }
1640
1641                 if (m is FieldInfo){
1642                         FieldInfo fi = (FieldInfo) m;
1643                         FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask;
1644
1645                         if (fa == FieldAttributes.Private)
1646                                 return closure_private_ok;
1647
1648                         //
1649                         // FamAndAssem requires that we not only derivate, but we are on the
1650                         // same assembly.  
1651                         //
1652                         if (fa == FieldAttributes.FamANDAssem){
1653                                 if (closure_invocation_assembly != fi.DeclaringType.Assembly)
1654                                         return false;
1655                         }
1656                         // FamORAssem, Family and Public:
1657                         return true;
1658                 }
1659
1660                 //
1661                 // EventInfos and PropertyInfos, return true
1662                 //
1663                 return true;
1664         }
1665
1666         static MemberFilter FilterWithClosure_delegate = new MemberFilter (FilterWithClosure);
1667         
1668         //
1669         // Looks up a member called `name' in the `queried_type'.  This lookup
1670         // is done by code that is contained in the definition for `invocation_type'.
1671         //
1672         // The binding flags are `bf' and the kind of members being looked up are `mt'
1673         //
1674         // Returns an array of a single element for everything but Methods/Constructors
1675         // that might return multiple matches.
1676         //
1677         public static MemberInfo [] MemberLookup (Type invocation_type, Type queried_type, 
1678                                                   MemberTypes mt, BindingFlags original_bf, string name)
1679         {
1680                 BindingFlags bf = original_bf;
1681                 
1682                 ArrayList method_list = null;
1683                 Type current_type = queried_type;
1684                 bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0;
1685                 bool private_ok;
1686                 bool always_ok_flag = false;
1687
1688                 closure_name = name;
1689                 closure_invocation_type = invocation_type;
1690                 closure_invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
1691
1692                 //
1693                 // If we are a nested class, we always have access to our container
1694                 // type names
1695                 //
1696                 if (invocation_type != null){
1697                         string invocation_name = invocation_type.FullName;
1698                         if (invocation_name.IndexOf ('+') != -1){
1699                                 string container = queried_type.FullName + "+";
1700                                 int container_length = container.Length;
1701                                 
1702                                 if (invocation_name.Length > container_length){
1703                                         string shared = invocation_name.Substring (0, container_length);
1704                                 
1705                                         if (shared == container)
1706                                                 always_ok_flag = true;
1707                                 }
1708                         }
1709                 }
1710                 
1711                 do {
1712                         MemberInfo [] mi;
1713
1714                         //
1715                         // `NonPublic' is lame, because it includes both protected and
1716                         // private methods, so we need to control this behavior by
1717                         // explicitly tracking if a private method is ok or not.
1718                         //
1719                         // The possible cases are:
1720                         //    public, private and protected (internal does not come into the
1721                         //    equation)
1722                         //
1723                         if (invocation_type != null){
1724                                 if (invocation_type == current_type){
1725                                         private_ok = true;
1726                                 } else
1727                                         private_ok = always_ok_flag;
1728                                 
1729                                 if (private_ok || invocation_type.IsSubclassOf (current_type))
1730                                         bf = original_bf | BindingFlags.NonPublic;
1731                         } else {
1732                                 private_ok = false;
1733                                 bf = original_bf & ~BindingFlags.NonPublic;
1734                         }
1735
1736                         closure_private_ok = private_ok;
1737                         closure_queried_type = current_type;
1738                         
1739                         mi = TypeManager.FindMembers (
1740                                 current_type, mt, bf | BindingFlags.DeclaredOnly,
1741                                 FilterWithClosure_delegate, name);
1742                         
1743                         if (current_type == TypeManager.object_type)
1744                                 searching = false;
1745                         else {
1746                                 current_type = current_type.BaseType;
1747                                 
1748                                 //
1749                                 // This happens with interfaces, they have a null
1750                                 // basetype.  Look members up in the Object class.
1751                                 //
1752                                 if (current_type == null)
1753                                         current_type = TypeManager.object_type;
1754                         }
1755                         
1756                         if (mi == null)
1757                                 continue;
1758                         
1759                         int count = mi.Length;
1760                         
1761                         if (count == 0)
1762                                 continue;
1763                         
1764                         //
1765                         // Events and types are returned by both `static' and `instance'
1766                         // searches, which means that our above FindMembers will
1767                         // return two copies of the same.
1768                         //
1769                         if (count == 1 && !(mi [0] is MethodBase)){
1770                                 return mi;
1771                         }
1772
1773                         //
1774                         // Multiple properties: we query those just to find out the indexer
1775                         // name
1776                         //
1777                         if (mi [0] is PropertyInfo)
1778                                 return mi;
1779                         
1780                         //
1781                         // We found methods, turn the search into "method scan"
1782                         // mode.
1783                         //
1784                         
1785                         method_list = CopyNewMethods (method_list, mi);
1786                         mt &= (MemberTypes.Method | MemberTypes.Constructor);
1787                 } while (searching);
1788
1789                 if (method_list != null && method_list.Count > 0)
1790                         return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
1791         
1792                 //
1793                 // Interfaces do not list members they inherit, so we have to
1794                 // scan those.
1795                 // 
1796                 if (!queried_type.IsInterface)
1797                         return null;
1798
1799                 if (queried_type.IsArray)
1800                         queried_type = TypeManager.array_type;
1801                 
1802                 Type [] ifaces = GetInterfaces (queried_type);
1803                 if (ifaces == null)
1804                         return null;
1805                 
1806                 foreach (Type itype in ifaces){
1807                         MemberInfo [] x;
1808
1809                         x = MemberLookup (null, itype, mt, bf, name);
1810                         if (x != null)
1811                                 return x;
1812                 }
1813                                         
1814                 return null;
1815         }
1816 #endregion
1817         
1818 }
1819
1820 }