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