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