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