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