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