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