2 // typemanager.cs: C# type manager
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 // Ravi Pratap (ravi@ximian.com)
7 // Licensed under the terms of the GNU GPL
9 // (C) 2001 Ximian, Inc (http://www.ximian.com)
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.
18 #define SIMPLE_SPEEDUP
22 using System.Globalization;
23 using System.Collections;
24 using System.Reflection;
25 using System.Reflection.Emit;
26 using System.Text.RegularExpressions;
27 using System.Runtime.CompilerServices;
28 using System.Diagnostics;
30 namespace Mono.CSharp {
32 public class TypeManager {
34 // A list of core types that the compiler requires or uses
36 static public Type object_type;
37 static public Type value_type;
38 static public Type string_type;
39 static public Type int32_type;
40 static public Type uint32_type;
41 static public Type int64_type;
42 static public Type uint64_type;
43 static public Type float_type;
44 static public Type double_type;
45 static public Type char_type;
46 static public Type char_ptr_type;
47 static public Type short_type;
48 static public Type decimal_type;
49 static public Type bool_type;
50 static public Type sbyte_type;
51 static public Type byte_type;
52 static public Type ushort_type;
53 static public Type enum_type;
54 static public Type delegate_type;
55 static public Type multicast_delegate_type;
56 static public Type void_type;
57 static public Type enumeration_type;
58 static public Type array_type;
59 static public Type runtime_handle_type;
60 static public Type icloneable_type;
61 static public Type type_type;
62 static public Type ienumerator_type;
63 static public Type idisposable_type;
64 static public Type default_member_type;
65 static public Type iasyncresult_type;
66 static public Type asynccallback_type;
67 static public Type intptr_type;
68 static public Type monitor_type;
69 static public Type runtime_field_handle_type;
70 static public Type attribute_type;
71 static public Type attribute_usage_type;
72 static public Type dllimport_type;
73 static public Type unverifiable_code_type;
74 static public Type methodimpl_attr_type;
75 static public Type marshal_as_attr_type;
76 static public Type param_array_type;
77 static public Type guid_attr_type;
78 static public Type void_ptr_type;
79 static public Type indexer_name_type;
80 static public Type exception_type;
81 static public object obsolete_attribute_type;
82 static public object conditional_attribute_type;
83 static public Type in_attribute_type;
86 // An empty array of types
88 static public Type [] NoTypes;
92 // Expressions representing the internal types. Used during declaration
95 static public Expression system_object_expr, system_string_expr;
96 static public Expression system_boolean_expr, system_decimal_expr;
97 static public Expression system_single_expr, system_double_expr;
98 static public Expression system_sbyte_expr, system_byte_expr;
99 static public Expression system_int16_expr, system_uint16_expr;
100 static public Expression system_int32_expr, system_uint32_expr;
101 static public Expression system_int64_expr, system_uint64_expr;
102 static public Expression system_char_expr, system_void_expr;
103 static public Expression system_asynccallback_expr;
104 static public Expression system_iasyncresult_expr;
107 // This is only used when compiling corlib
109 static public Type system_int32_type;
110 static public Type system_array_type;
111 static public Type system_type_type;
112 static public Type system_assemblybuilder_type;
113 static public MethodInfo system_int_array_get_length;
114 static public MethodInfo system_int_array_get_rank;
115 static public MethodInfo system_object_array_clone;
116 static public MethodInfo system_int_array_get_length_int;
117 static public MethodInfo system_int_array_get_lower_bound_int;
118 static public MethodInfo system_int_array_get_upper_bound_int;
119 static public MethodInfo system_void_array_copyto_array_int;
120 static public MethodInfo system_void_set_corlib_type_builders;
124 // Internal, not really used outside
126 static Type runtime_helpers_type;
129 // These methods are called by code generated by the compiler
131 static public MethodInfo string_concat_string_string;
132 static public MethodInfo string_concat_string_string_string;
133 static public MethodInfo string_concat_string_string_string_string;
134 static public MethodInfo string_concat_object_object;
135 static public MethodInfo string_isinterneted_string;
136 static public MethodInfo system_type_get_type_from_handle;
137 static public MethodInfo object_getcurrent_void;
138 static public MethodInfo bool_movenext_void;
139 static public MethodInfo void_dispose_void;
140 static public MethodInfo void_monitor_enter_object;
141 static public MethodInfo void_monitor_exit_object;
142 static public MethodInfo void_initializearray_array_fieldhandle;
143 static public MethodInfo int_getlength_int;
144 static public MethodInfo delegate_combine_delegate_delegate;
145 static public MethodInfo delegate_remove_delegate_delegate;
146 static public MethodInfo int_get_offset_to_string_data;
147 static public MethodInfo int_array_get_length;
148 static public MethodInfo int_array_get_rank;
149 static public MethodInfo object_array_clone;
150 static public MethodInfo int_array_get_length_int;
151 static public MethodInfo int_array_get_lower_bound_int;
152 static public MethodInfo int_array_get_upper_bound_int;
153 static public MethodInfo void_array_copyto_array_int;
156 // The attribute constructors.
158 static public ConstructorInfo cons_param_array_attribute;
159 static public ConstructorInfo void_decimal_ctor_five_args;
160 static public ConstructorInfo unverifiable_code_ctor;
163 // Holds the Array of Assemblies that have been loaded
164 // (either because it is the default or the user used the
165 // -r command line option)
167 static Assembly [] assemblies;
170 // Keeps a list of module builders. We used this to do lookups
171 // on the modulebuilder using GetType -- needed for arrays
173 static ModuleBuilder [] modules;
176 // This is the type_cache from the assemblies to avoid
177 // hitting System.Reflection on every lookup.
179 static Hashtable types;
182 // This is used to hotld the corresponding TypeContainer objects
183 // since we need this in FindMembers
185 static Hashtable typecontainers;
188 // Keeps track of those types that are defined by the
191 static ArrayList user_types;
193 static PtrHashtable builder_to_declspace;
196 // Tracks the interfaces implemented by typebuilders. We only
197 // enter those who do implement or or more interfaces
199 static PtrHashtable builder_to_ifaces;
202 // Maps MethodBase.RuntimeTypeHandle to a Type array that contains
203 // the arguments to the method
205 static Hashtable method_arguments;
208 // Maps PropertyBuilder to a Type array that contains
209 // the arguments to the indexer
211 static Hashtable indexer_arguments;
214 // Maybe `method_arguments' should be replaced and only
215 // method_internal_params should be kept?
217 static Hashtable method_internal_params;
220 // Keeps track of attribute types
223 static Hashtable builder_to_attr;
226 // Keeps track of methods
229 static Hashtable builder_to_method;
237 /// A filter for Findmembers that uses the Signature object to
240 static bool SignatureFilter (MemberInfo mi, object criteria)
242 Signature sig = (Signature) criteria;
244 if (!(mi is MethodBase))
247 if (mi.Name != sig.name)
250 int count = sig.args.Length;
252 if (mi is MethodBuilder || mi is ConstructorBuilder){
253 Type [] candidate_args = GetArgumentTypes ((MethodBase) mi);
255 if (candidate_args.Length != count)
258 for (int i = 0; i < count; i++)
259 if (candidate_args [i] != sig.args [i])
264 ParameterInfo [] pars = ((MethodBase) mi).GetParameters ();
266 if (pars.Length != count)
269 for (int i = 0; i < count; i++)
270 if (pars [i].ParameterType != sig.args [i])
276 // A delegate that points to the filter above.
277 static MemberFilter signature_filter;
280 // These are expressions that represent some of the internal data types, used
283 static void InitExpressionTypes ()
285 system_object_expr = new TypeLookupExpression ("System.Object");
286 system_string_expr = new TypeLookupExpression ("System.String");
287 system_boolean_expr = new TypeLookupExpression ("System.Boolean");
288 system_decimal_expr = new TypeLookupExpression ("System.Decimal");
289 system_single_expr = new TypeLookupExpression ("System.Single");
290 system_double_expr = new TypeLookupExpression ("System.Double");
291 system_sbyte_expr = new TypeLookupExpression ("System.SByte");
292 system_byte_expr = new TypeLookupExpression ("System.Byte");
293 system_int16_expr = new TypeLookupExpression ("System.Int16");
294 system_uint16_expr = new TypeLookupExpression ("System.UInt16");
295 system_int32_expr = new TypeLookupExpression ("System.Int32");
296 system_uint32_expr = new TypeLookupExpression ("System.UInt32");
297 system_int64_expr = new TypeLookupExpression ("System.Int64");
298 system_uint64_expr = new TypeLookupExpression ("System.UInt64");
299 system_char_expr = new TypeLookupExpression ("System.Char");
300 system_void_expr = new TypeLookupExpression ("System.Void");
301 system_asynccallback_expr = new TypeLookupExpression ("System.AsyncCallback");
302 system_iasyncresult_expr = new TypeLookupExpression ("System.IAsyncResult");
305 static TypeManager ()
307 assemblies = new Assembly [0];
309 user_types = new ArrayList ();
311 types = new Hashtable ();
312 typecontainers = new Hashtable ();
314 builder_to_declspace = new PtrHashtable ();
315 builder_to_attr = new PtrHashtable ();
316 builder_to_method = new PtrHashtable ();
317 method_arguments = new PtrHashtable ();
318 method_internal_params = new PtrHashtable ();
319 indexer_arguments = new PtrHashtable ();
320 builder_to_ifaces = new PtrHashtable ();
322 NoTypes = new Type [0];
324 signature_filter = new MemberFilter (SignatureFilter);
325 InitExpressionTypes ();
328 public static void AddUserType (string name, TypeBuilder t, Type [] ifaces)
333 Type prev = (Type) types [name];
334 TypeContainer tc = builder_to_declspace [prev] as TypeContainer;
338 // This probably never happens, as we catch this before
340 Report.Error (-17, "The type `" + name + "' has already been defined.");
344 tc = builder_to_declspace [t] as TypeContainer;
347 1595, "The type `" + name + "' is defined in an existing assembly;"+
348 " Using the new definition from: " + tc.Location);
349 Report.Warning (1595, "Previously defined in: " + prev.Assembly.FullName);
357 builder_to_ifaces [t] = ifaces;
361 // This entry point is used by types that we define under the covers
363 public static void RegisterBuilder (TypeBuilder tb, Type [] ifaces)
366 builder_to_ifaces [tb] = ifaces;
369 public static void AddUserType (string name, TypeBuilder t, TypeContainer tc, Type [] ifaces)
371 builder_to_declspace.Add (t, tc);
372 typecontainers.Add (name, tc);
373 AddUserType (name, t, ifaces);
376 public static void AddDelegateType (string name, TypeBuilder t, Delegate del)
379 builder_to_declspace.Add (t, del);
382 public static void AddEnumType (string name, TypeBuilder t, Enum en)
385 builder_to_declspace.Add (t, en);
388 public static void AddUserInterface (string name, TypeBuilder t, Interface i, Type [] ifaces)
390 AddUserType (name, t, ifaces);
391 builder_to_declspace.Add (t, i);
394 public static void AddMethod (MethodBuilder builder, MethodData method)
396 builder_to_method.Add (builder, method);
399 public static void RegisterAttrType (Type t, TypeContainer tc)
401 builder_to_attr.Add (t, tc);
405 /// Returns the TypeContainer whose Type is `t' or null if there is no
406 /// TypeContainer for `t' (ie, the Type comes from a library)
408 public static TypeContainer LookupTypeContainer (Type t)
410 return builder_to_declspace [t] as TypeContainer;
413 public static IMemberContainer LookupMemberContainer (Type t)
415 if (t is TypeBuilder) {
416 IMemberContainer container = builder_to_declspace [t] as IMemberContainer;
417 if (container != null)
421 return TypeHandle.GetTypeHandle (t);
424 public static Interface LookupInterface (Type t)
426 return builder_to_declspace [t] as Interface;
429 public static Delegate LookupDelegate (Type t)
431 return builder_to_declspace [t] as Delegate;
434 public static Enum LookupEnum (Type t)
436 return builder_to_declspace [t] as Enum;
439 public static TypeContainer LookupAttr (Type t)
441 return (TypeContainer) builder_to_attr [t];
445 /// Registers an assembly to load types from.
447 public static void AddAssembly (Assembly a)
449 int top = assemblies.Length;
450 Assembly [] n = new Assembly [top + 1];
452 assemblies.CopyTo (n, 0);
459 /// Registers a module builder to lookup types from
461 public static void AddModule (ModuleBuilder mb)
463 int top = modules != null ? modules.Length : 0;
464 ModuleBuilder [] n = new ModuleBuilder [top + 1];
467 modules.CopyTo (n, 0);
473 // Low-level lookup, cache-less
475 static Type LookupTypeReflection (string name)
479 foreach (Assembly a in assemblies){
480 t = a.GetType (name);
485 foreach (ModuleBuilder mb in modules) {
486 t = mb.GetType (name);
494 static Hashtable negative_hits = new Hashtable ();
497 // This function is used when you want to avoid the lookups, and want to go
498 // directly to the source. This will use the cache.
500 // Notice that bypassing the cache is bad, because on Microsoft.NET runtime
501 // GetType ("DynamicType[]") != GetType ("DynamicType[]"), and there is no
502 // way to test things other than doing a fullname compare
504 public static Type LookupTypeDirect (string name)
506 Type t = (Type) types [name];
510 t = LookupTypeReflection (name);
519 /// Returns the Type associated with @name, takes care of the fact that
520 /// reflection expects nested types to be separated from the main type
521 /// with a "+" instead of a "."
523 public static Type LookupType (string name)
528 // First lookup in user defined and cached values
531 t = (Type) types [name];
536 if (negative_hits.Contains (name))
541 // Optimization: ComposedCast will work with an existing type, and might already have the
542 // full name of the type, so the full system lookup can probably be avoided.
545 string [] elements = name.Split ('.');
546 int count = elements.Length;
548 for (int n = 1; n <= count; n++){
549 string top_level_type = String.Join (".", elements, 0, n);
551 t = (Type) types [top_level_type];
553 t = LookupTypeReflection (top_level_type);
564 // We know that System.Object does not have children, and since its the parent of
565 // all the objects, it always gets probbed for inner classes.
567 if (top_level_type == "System.Object")
570 string newt = top_level_type + "+" + String.Join ("+", elements, n, count - n);
571 t = LookupTypeDirect (newt);
578 negative_hits [name] = true;
583 static Hashtable assemblies_namespaces = new Hashtable ();
586 // Returns a list of all namespaces in the assemblies and types loaded.
588 static Hashtable ExtractAssemblyNamespaces ()
590 foreach (Assembly a in assemblies){
591 foreach (Type t in a.GetTypes ()){
592 string ns = t.Namespace;
594 if (assemblies_namespaces.Contains (ns))
596 assemblies_namespaces [ns] = ns;
600 return assemblies_namespaces;
603 static Hashtable AddModuleNamespaces (Hashtable h)
605 foreach (ModuleBuilder mb in modules){
606 foreach (Type t in mb.GetTypes ()){
607 string ns = t.Namespace;
619 /// Returns the list of namespaces that are active for this executable
621 public static Hashtable GetAssemblyNamespaces (string executable_name)
623 string cache_name = executable_name + ".nsc";
624 Hashtable cached_namespaces = LoadCache (cache_name);
626 if (cached_namespaces != null)
627 assemblies_namespaces = cached_namespaces;
629 Console.WriteLine ("rebuilding namespace cache");
630 assemblies_namespaces = ExtractAssemblyNamespaces ();
631 SaveCache (cache_name);
634 return assemblies_namespaces;
637 public static Hashtable GetNamespaces ()
639 if (assemblies_namespaces == null)
640 assemblies_namespaces = ExtractAssemblyNamespaces ();
642 Hashtable nh = (Hashtable) assemblies_namespaces.Clone ();
644 return AddModuleNamespaces (nh);
648 // Loads the namespace cache for the given executable name
650 static Hashtable LoadCache (string cache_file)
652 if (!File.Exists (cache_file)){
653 Console.WriteLine ("Cache not found");
658 Hashtable cached_module_list, cached_namespaces;
660 using (FileStream fs = File.OpenRead (cache_file)){
661 StreamReader reader = new StreamReader (fs);
663 int assembly_count = Int32.Parse (reader.ReadLine ());
665 if (assembly_count != assemblies.Length){
666 Console.WriteLine ("Assembly missmatch ({0}, {1})", assembly_count, assemblies.Length);
670 int namespace_count = Int32.Parse (reader.ReadLine ());
672 cached_module_list = new Hashtable (assembly_count);
673 for (int i = 0; i < assembly_count; i++)
674 cached_module_list [reader.ReadLine ()] = true;
676 cached_namespaces = new Hashtable (namespace_count);
677 for (int i = 0; i < namespace_count; i++){
678 string s = reader.ReadLine ();
679 cached_namespaces [s] = s;
684 // Now, check that the cache is still valid
687 foreach (Assembly a in assemblies)
688 if (cached_module_list [a.CodeBase] == null){
689 Console.WriteLine ("assembly not found in cache: " + a.CodeBase);
693 return cached_namespaces;
699 static void SaveCache (string cache_file)
702 using (FileStream fs = File.OpenWrite (cache_file)){
703 StreamWriter writer = new StreamWriter (fs);
705 writer.WriteLine (assemblies.Length);
706 writer.WriteLine (assemblies_namespaces.Count);
708 foreach (Assembly a in assemblies)
709 writer.WriteLine (a.CodeBase);
711 foreach (DictionaryEntry de in assemblies_namespaces){
712 writer.WriteLine ((string) de.Key);
718 } catch (Exception e) {
719 Console.WriteLine ("Failed: " + e);
724 public static void GetAllTypes ()
726 Hashtable namespaces = new Hashtable ();
728 foreach (Assembly a in assemblies){
729 foreach (Type t in a.GetTypes ()){
733 foreach (ModuleBuilder mb in modules){
734 foreach (Type t in mb.GetTypes ()){
741 /// Returns the C# name of a type if possible, or the full type name otherwise
743 static public string CSharpName (Type t)
745 return Regex.Replace (t.FullName,
747 @"(Int32|UInt32|Int16|Uint16|Int64|UInt64|" +
748 @"Single|Double|Char|Decimal|Byte|SByte|Object|" +
749 @"Boolean|String|Void)" +
751 new MatchEvaluator (CSharpNameMatch));
754 static String CSharpNameMatch (Match match)
756 string s = match.Groups [1].Captures [0].Value;
758 Replace ("int32", "int").
759 Replace ("uint32", "uint").
760 Replace ("int16", "short").
761 Replace ("uint16", "ushort").
762 Replace ("int64", "long").
763 Replace ("uint64", "ulong").
764 Replace ("single", "float").
765 Replace ("boolean", "bool")
766 + match.Groups [2].Captures [0].Value;
770 /// Returns the signature of the method
772 static public string CSharpSignature (MethodBase mb)
777 // FIXME: We should really have a single function to do
778 // everything instead of the following 5 line pattern
780 ParameterData iparams = LookupParametersByBuilder (mb);
782 if (iparams == null){
783 ParameterInfo [] pi = mb.GetParameters ();
784 iparams = new ReflectionParameters (pi);
787 for (int i = 0; i < iparams.Count; i++) {
791 sig += iparams.ParameterDesc(i);
795 return mb.DeclaringType.Name + "." + mb.Name + sig;
799 /// Looks up a type, and aborts if it is not found. This is used
800 /// by types required by the compiler
802 static Type CoreLookupType (string name)
804 Type t = LookupType (name);
807 Report.Error (518, "The predefined type `" + name + "' is not defined or imported");
808 Environment.Exit (0);
815 /// Returns the MethodInfo for a method named `name' defined
816 /// in type `t' which takes arguments of types `args'
818 static MethodInfo GetMethod (Type t, string name, Type [] args)
826 list = FindMembers (t, MemberTypes.Method, instance_and_static | BindingFlags.Public,
827 signature_filter, sig);
828 if (list.Count == 0) {
829 Report.Error (-19, "Can not find the core function `" + name + "'");
833 MethodInfo mi = list [0] as MethodInfo;
835 Report.Error (-19, "Can not find the core function `" + name + "'");
843 /// Returns the ConstructorInfo for "args"
845 static ConstructorInfo GetConstructor (Type t, Type [] args)
853 list = FindMembers (t, MemberTypes.Constructor,
854 instance_and_static | BindingFlags.Public | BindingFlags.DeclaredOnly,
855 signature_filter, sig);
856 if (list.Count == 0){
857 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
861 ConstructorInfo ci = list [0] as ConstructorInfo;
863 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
870 public static void InitEnumUnderlyingTypes ()
873 int32_type = CoreLookupType ("System.Int32");
874 int64_type = CoreLookupType ("System.Int64");
875 uint32_type = CoreLookupType ("System.UInt32");
876 uint64_type = CoreLookupType ("System.UInt64");
877 byte_type = CoreLookupType ("System.Byte");
878 sbyte_type = CoreLookupType ("System.SByte");
879 short_type = CoreLookupType ("System.Int16");
880 ushort_type = CoreLookupType ("System.UInt16");
884 /// The types have to be initialized after the initial
885 /// population of the type has happened (for example, to
886 /// bootstrap the corlib.dll
888 public static void InitCoreTypes ()
890 object_type = CoreLookupType ("System.Object");
891 value_type = CoreLookupType ("System.ValueType");
893 InitEnumUnderlyingTypes ();
895 char_type = CoreLookupType ("System.Char");
896 string_type = CoreLookupType ("System.String");
897 float_type = CoreLookupType ("System.Single");
898 double_type = CoreLookupType ("System.Double");
899 char_ptr_type = CoreLookupType ("System.Char*");
900 decimal_type = CoreLookupType ("System.Decimal");
901 bool_type = CoreLookupType ("System.Boolean");
902 enum_type = CoreLookupType ("System.Enum");
904 multicast_delegate_type = CoreLookupType ("System.MulticastDelegate");
905 delegate_type = CoreLookupType ("System.Delegate");
907 array_type = CoreLookupType ("System.Array");
908 void_type = CoreLookupType ("System.Void");
909 type_type = CoreLookupType ("System.Type");
911 runtime_field_handle_type = CoreLookupType ("System.RuntimeFieldHandle");
912 runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices.RuntimeHelpers");
913 default_member_type = CoreLookupType ("System.Reflection.DefaultMemberAttribute");
914 runtime_handle_type = CoreLookupType ("System.RuntimeTypeHandle");
915 asynccallback_type = CoreLookupType ("System.AsyncCallback");
916 iasyncresult_type = CoreLookupType ("System.IAsyncResult");
917 ienumerator_type = CoreLookupType ("System.Collections.IEnumerator");
918 idisposable_type = CoreLookupType ("System.IDisposable");
919 icloneable_type = CoreLookupType ("System.ICloneable");
920 monitor_type = CoreLookupType ("System.Threading.Monitor");
921 intptr_type = CoreLookupType ("System.IntPtr");
923 attribute_type = CoreLookupType ("System.Attribute");
924 attribute_usage_type = CoreLookupType ("System.AttributeUsageAttribute");
925 dllimport_type = CoreLookupType ("System.Runtime.InteropServices.DllImportAttribute");
926 methodimpl_attr_type = CoreLookupType ("System.Runtime.CompilerServices.MethodImplAttribute");
927 marshal_as_attr_type = CoreLookupType ("System.Runtime.InteropServices.MarshalAsAttribute");
928 param_array_type = CoreLookupType ("System.ParamArrayAttribute");
929 in_attribute_type = CoreLookupType ("System.Runtime.InteropServices.InAttribute");
932 // Temporary while people upgrade their corlibs
935 // Change from LookupType to CoreLookupType before release
937 guid_attr_type = LookupType ("System.Runtime.InteropServices.GuidAttribute");
939 unverifiable_code_type= CoreLookupType ("System.Security.UnverifiableCodeAttribute");
941 void_ptr_type = CoreLookupType ("System.Void*");
943 indexer_name_type = CoreLookupType ("System.Runtime.CompilerServices.IndexerNameAttribute");
945 exception_type = CoreLookupType ("System.Exception");
950 obsolete_attribute_type = CoreLookupType ("System.ObsoleteAttribute");
951 conditional_attribute_type = CoreLookupType ("System.Diagnostics.ConditionalAttribute");
954 // When compiling corlib, store the "real" types here.
956 if (!RootContext.StdLib) {
957 system_int32_type = typeof (System.Int32);
958 system_array_type = typeof (System.Array);
959 system_type_type = typeof (System.Type);
960 system_assemblybuilder_type = typeof (System.Reflection.Emit.AssemblyBuilder);
962 Type [] void_arg = { };
963 system_int_array_get_length = GetMethod (
964 system_array_type, "get_Length", void_arg);
965 system_int_array_get_rank = GetMethod (
966 system_array_type, "get_Rank", void_arg);
967 system_object_array_clone = GetMethod (
968 system_array_type, "Clone", void_arg);
970 Type [] system_int_arg = { system_int32_type };
971 system_int_array_get_length_int = GetMethod (
972 system_array_type, "GetLength", system_int_arg);
973 system_int_array_get_upper_bound_int = GetMethod (
974 system_array_type, "GetUpperBound", system_int_arg);
975 system_int_array_get_lower_bound_int = GetMethod (
976 system_array_type, "GetLowerBound", system_int_arg);
978 Type [] system_array_int_arg = { system_array_type, system_int32_type };
979 system_void_array_copyto_array_int = GetMethod (
980 system_array_type, "CopyTo", system_array_int_arg);
982 Type [] system_type_type_arg = { system_type_type, system_type_type, system_type_type };
985 system_void_set_corlib_type_builders = GetMethod (
986 system_assemblybuilder_type, "SetCorlibTypeBuilders",
987 system_type_type_arg);
989 object[] args = new object [3];
990 args [0] = object_type;
991 args [1] = value_type;
992 args [2] = enum_type;
994 system_void_set_corlib_type_builders.Invoke (CodeGen.AssemblyBuilder, args);
996 Console.WriteLine ("Corlib compilation is not supported in Microsoft.NET due to bugs in it");
1002 // The helper methods that are used by the compiler
1004 public static void InitCodeHelpers ()
1007 // Now load the default methods that we use.
1009 Type [] string_string = { string_type, string_type };
1010 string_concat_string_string = GetMethod (
1011 string_type, "Concat", string_string);
1012 Type [] string_string_string = { string_type, string_type, string_type };
1013 string_concat_string_string_string = GetMethod (
1014 string_type, "Concat", string_string_string);
1015 Type [] string_string_string_string = { string_type, string_type, string_type, string_type };
1016 string_concat_string_string_string_string = GetMethod (
1017 string_type, "Concat", string_string_string_string);
1019 Type [] object_object = { object_type, object_type };
1020 string_concat_object_object = GetMethod (
1021 string_type, "Concat", object_object);
1023 Type [] string_ = { string_type };
1024 string_isinterneted_string = GetMethod (
1025 string_type, "IsInterned", string_);
1027 Type [] runtime_type_handle = { runtime_handle_type };
1028 system_type_get_type_from_handle = GetMethod (
1029 type_type, "GetTypeFromHandle", runtime_type_handle);
1031 Type [] delegate_delegate = { delegate_type, delegate_type };
1032 delegate_combine_delegate_delegate = GetMethod (
1033 delegate_type, "Combine", delegate_delegate);
1035 delegate_remove_delegate_delegate = GetMethod (
1036 delegate_type, "Remove", delegate_delegate);
1041 Type [] void_arg = { };
1042 object_getcurrent_void = GetMethod (
1043 ienumerator_type, "get_Current", void_arg);
1044 bool_movenext_void = GetMethod (
1045 ienumerator_type, "MoveNext", void_arg);
1046 void_dispose_void = GetMethod (
1047 idisposable_type, "Dispose", void_arg);
1048 int_get_offset_to_string_data = GetMethod (
1049 runtime_helpers_type, "get_OffsetToStringData", void_arg);
1050 int_array_get_length = GetMethod (
1051 array_type, "get_Length", void_arg);
1052 int_array_get_rank = GetMethod (
1053 array_type, "get_Rank", void_arg);
1058 Type [] int_arg = { int32_type };
1059 int_array_get_length_int = GetMethod (
1060 array_type, "GetLength", int_arg);
1061 int_array_get_upper_bound_int = GetMethod (
1062 array_type, "GetUpperBound", int_arg);
1063 int_array_get_lower_bound_int = GetMethod (
1064 array_type, "GetLowerBound", int_arg);
1067 // System.Array methods
1069 object_array_clone = GetMethod (
1070 array_type, "Clone", void_arg);
1071 Type [] array_int_arg = { array_type, int32_type };
1072 void_array_copyto_array_int = GetMethod (
1073 array_type, "CopyTo", array_int_arg);
1078 Type [] object_arg = { object_type };
1079 void_monitor_enter_object = GetMethod (
1080 monitor_type, "Enter", object_arg);
1081 void_monitor_exit_object = GetMethod (
1082 monitor_type, "Exit", object_arg);
1084 Type [] array_field_handle_arg = { array_type, runtime_field_handle_type };
1086 void_initializearray_array_fieldhandle = GetMethod (
1087 runtime_helpers_type, "InitializeArray", array_field_handle_arg);
1092 int_getlength_int = GetMethod (
1093 array_type, "GetLength", int_arg);
1096 // Decimal constructors
1098 Type [] dec_arg = { int32_type, int32_type, int32_type, bool_type, byte_type };
1099 void_decimal_ctor_five_args = GetConstructor (
1100 decimal_type, dec_arg);
1105 cons_param_array_attribute = GetConstructor (
1106 param_array_type, void_arg);
1108 unverifiable_code_ctor = GetConstructor (
1109 unverifiable_code_type, void_arg);
1113 const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance;
1115 static Hashtable type_hash = new Hashtable ();
1118 /// This is the "old", non-cache based FindMembers() function. We cannot use
1119 /// the cache here because there is no member name argument.
1121 public static MemberList FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1122 MemberFilter filter, object criteria)
1124 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
1127 // `builder_to_declspace' contains all dynamic types.
1131 Timer.StartTimer (TimerType.FindMembers);
1132 list = decl.FindMembers (mt, bf, filter, criteria);
1133 Timer.StopTimer (TimerType.FindMembers);
1138 // We have to take care of arrays specially, because GetType on
1139 // a TypeBuilder array will return a Type, not a TypeBuilder,
1140 // and we can not call FindMembers on this type.
1142 if (t.IsSubclassOf (TypeManager.array_type))
1143 return new MemberList (TypeManager.array_type.FindMembers (mt, bf, filter, criteria));
1146 // Since FindMembers will not lookup both static and instance
1147 // members, we emulate this behaviour here.
1149 if ((bf & instance_and_static) == instance_and_static){
1150 MemberInfo [] i_members = t.FindMembers (
1151 mt, bf & ~BindingFlags.Static, filter, criteria);
1153 int i_len = i_members.Length;
1155 MemberInfo one = i_members [0];
1158 // If any of these are present, we are done!
1160 if ((one is Type) || (one is EventInfo) || (one is FieldInfo))
1161 return new MemberList (i_members);
1164 MemberInfo [] s_members = t.FindMembers (
1165 mt, bf & ~BindingFlags.Instance, filter, criteria);
1167 int s_len = s_members.Length;
1168 if (i_len > 0 || s_len > 0)
1169 return new MemberList (i_members, s_members);
1172 return new MemberList (i_members);
1174 return new MemberList (s_members);
1178 return new MemberList (t.FindMembers (mt, bf, filter, criteria));
1183 /// This method is only called from within MemberLookup. It tries to use the member
1184 /// cache if possible and falls back to the normal FindMembers if not. The `used_cache'
1185 /// flag tells the caller whether we used the cache or not. If we used the cache, then
1186 /// our return value will already contain all inherited members and the caller don't need
1187 /// to check base classes and interfaces anymore.
1189 private static MemberList MemberLookup_FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1190 string name, out bool used_cache)
1193 // We have to take care of arrays specially, because GetType on
1194 // a TypeBuilder array will return a Type, not a TypeBuilder,
1195 // and we can not call FindMembers on this type.
1197 if (t == TypeManager.array_type || t.IsSubclassOf (TypeManager.array_type)) {
1199 return TypeHandle.ArrayType.MemberCache.FindMembers (
1200 mt, bf, name, FilterWithClosure_delegate, null);
1204 // If this is a dynamic type, it's always in the `builder_to_declspace' hash table
1205 // and we can ask the DeclSpace for the MemberCache.
1207 if (t is TypeBuilder) {
1208 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
1209 MemberCache cache = decl.MemberCache;
1212 // If this DeclSpace has a MemberCache, use it.
1215 if (cache != null) {
1217 return cache.FindMembers (
1218 mt, bf, name, FilterWithClosure_delegate, null);
1221 // If there is no MemberCache, we need to use the "normal" FindMembers.
1224 Timer.StartTimer (TimerType.FindMembers);
1225 list = decl.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
1226 FilterWithClosure_delegate, name);
1227 Timer.StopTimer (TimerType.FindMembers);
1233 // This call will always succeed. There is exactly one TypeHandle instance per
1234 // type, TypeHandle.GetTypeHandle() will either return it or create a new one
1235 // if it didn't already exist.
1237 TypeHandle handle = TypeHandle.GetTypeHandle (t);
1240 return handle.MemberCache.FindMembers (mt, bf, name, FilterWithClosure_delegate, null);
1243 public static bool IsBuiltinType (Type t)
1245 if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
1246 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1247 t == char_type || t == short_type || t == decimal_type || t == bool_type ||
1248 t == sbyte_type || t == byte_type || t == ushort_type || t == void_type)
1255 // This is like IsBuiltinType, but lacks decimal_type, we should also clean up
1256 // the pieces in the code where we use IsBuiltinType and special case decimal_type.
1258 public static bool IsCLRType (Type t)
1260 if (t == object_type || t == int32_type || t == uint32_type ||
1261 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1262 t == char_type || t == short_type || t == bool_type ||
1263 t == sbyte_type || t == byte_type || t == ushort_type)
1269 public static bool IsDelegateType (Type t)
1271 if (t.IsSubclassOf (TypeManager.delegate_type))
1277 public static bool IsEnumType (Type t)
1279 if (t == TypeManager.enum_type || t.IsSubclassOf (TypeManager.enum_type))
1286 // Whether a type is unmanaged. This is used by the unsafe code (25.2)
1288 public static bool IsUnmanagedType (Type t)
1290 if (IsBuiltinType (t) && t != TypeManager.string_type)
1299 if (IsValueType (t)){
1300 if (t is TypeBuilder){
1301 TypeContainer tc = LookupTypeContainer (t);
1303 foreach (Field f in tc.Fields){
1304 if (f.FieldBuilder.IsStatic)
1306 if (!IsUnmanagedType (f.FieldBuilder.FieldType))
1310 FieldInfo [] fields = t.GetFields ();
1312 foreach (FieldInfo f in fields){
1315 if (!IsUnmanagedType (f.FieldType))
1325 public static bool IsValueType (Type t)
1327 if (t.IsSubclassOf (TypeManager.value_type))
1333 public static bool IsInterfaceType (Type t)
1335 Interface iface = builder_to_declspace [t] as Interface;
1344 // Checks whether `type' is a subclass or nested child of `parent'.
1346 public static bool IsSubclassOrNestedChildOf (Type type, Type parent)
1349 if ((type == parent) || type.IsSubclassOf (parent))
1352 // Handle nested types.
1353 type = type.DeclaringType;
1354 } while (type != null);
1360 // Checks whether `type' is a nested child of `parent'.
1362 public static bool IsNestedChildOf (Type type, Type parent)
1364 if ((type == parent) || type.IsSubclassOf (parent))
1367 return IsSubclassOrNestedChildOf (type, parent);
1371 /// Returns the User Defined Types
1373 public static ArrayList UserTypes {
1379 public static Hashtable TypeContainers {
1381 return typecontainers;
1385 static Hashtable attr_to_allowmult;
1387 public static void RegisterAttributeAllowMultiple (Type attr_type, bool allow)
1389 if (attr_to_allowmult == null)
1390 attr_to_allowmult = new PtrHashtable ();
1392 if (attr_to_allowmult.Contains (attr_type))
1395 attr_to_allowmult.Add (attr_type, allow);
1399 public static bool AreMultipleAllowed (Type attr_type)
1401 if (!(attr_type is TypeBuilder)) {
1402 System.Attribute [] attrs = System.Attribute.GetCustomAttributes (attr_type);
1404 foreach (System.Attribute tmp in attrs)
1405 if (tmp is AttributeUsageAttribute)
1406 return ((AttributeUsageAttribute) tmp).AllowMultiple;
1411 if (attr_to_allowmult == null)
1414 return (bool) attr_to_allowmult [attr_type];
1417 static Hashtable builder_to_constant;
1419 public static void RegisterConstant (FieldBuilder fb, Const c)
1421 if (builder_to_constant == null)
1422 builder_to_constant = new PtrHashtable ();
1424 if (builder_to_constant.Contains (fb))
1427 builder_to_constant.Add (fb, c);
1430 public static Const LookupConstant (FieldBuilder fb)
1432 if (builder_to_constant == null)
1435 return (Const) builder_to_constant [fb];
1439 /// Gigantic work around for missing features in System.Reflection.Emit follows.
1443 /// Since System.Reflection.Emit can not return MethodBase.GetParameters
1444 /// for anything which is dynamic, and we need this in a number of places,
1445 /// we register this information here, and use it afterwards.
1447 static public bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] args)
1452 method_arguments.Add (mb, args);
1453 method_internal_params.Add (mb, ip);
1458 static public InternalParameters LookupParametersByBuilder (MethodBase mb)
1460 if (! (mb is ConstructorBuilder || mb is MethodBuilder))
1463 if (method_internal_params.Contains (mb))
1464 return (InternalParameters) method_internal_params [mb];
1466 throw new Exception ("Argument for Method not registered" + mb);
1470 /// Returns the argument types for a method based on its methodbase
1472 /// For dynamic methods, we use the compiler provided types, for
1473 /// methods from existing assemblies we load them from GetParameters,
1474 /// and insert them into the cache
1476 static public Type [] GetArgumentTypes (MethodBase mb)
1478 if (method_arguments.Contains (mb))
1479 return (Type []) method_arguments [mb];
1481 ParameterInfo [] pi = mb.GetParameters ();
1483 Type [] types = new Type [c];
1485 for (int i = 0; i < c; i++)
1486 types [i] = pi [i].ParameterType;
1488 method_arguments.Add (mb, types);
1494 /// Returns the argument types for an indexer based on its PropertyInfo
1496 /// For dynamic indexers, we use the compiler provided types, for
1497 /// indexers from existing assemblies we load them from GetParameters,
1498 /// and insert them into the cache
1500 static public Type [] GetArgumentTypes (PropertyInfo indexer)
1502 if (indexer_arguments.Contains (indexer))
1503 return (Type []) indexer_arguments [indexer];
1504 else if (indexer is PropertyBuilder)
1505 // If we're a PropertyBuilder and not in the
1506 // `indexer_arguments' hash, then we're a property and
1510 ParameterInfo [] pi = indexer.GetIndexParameters ();
1511 // Property, not an indexer.
1515 Type [] types = new Type [c];
1517 for (int i = 0; i < c; i++)
1518 types [i] = pi [i].ParameterType;
1520 indexer_arguments.Add (indexer, types);
1526 // This is a workaround the fact that GetValue is not
1527 // supported for dynamic types
1529 static Hashtable fields = new Hashtable ();
1530 static public bool RegisterFieldValue (FieldBuilder fb, object value)
1532 if (fields.Contains (fb))
1535 fields.Add (fb, value);
1540 static public object GetValue (FieldBuilder fb)
1545 static Hashtable fieldbuilders_to_fields = new Hashtable ();
1546 static public bool RegisterFieldBase (FieldBuilder fb, FieldBase f)
1548 if (fieldbuilders_to_fields.Contains (fb))
1551 fieldbuilders_to_fields.Add (fb, f);
1555 static public FieldBase GetField (FieldInfo fb)
1557 return (FieldBase) fieldbuilders_to_fields [fb];
1560 static Hashtable events;
1562 static public bool RegisterEvent (MyEventBuilder eb, MethodBase add, MethodBase remove)
1565 events = new Hashtable ();
1567 if (events.Contains (eb))
1570 events.Add (eb, new Pair (add, remove));
1575 static public MethodInfo GetAddMethod (EventInfo ei)
1577 if (ei is MyEventBuilder) {
1578 Pair pair = (Pair) events [ei];
1580 return (MethodInfo) pair.First;
1582 return ei.GetAddMethod ();
1585 static public MethodInfo GetRemoveMethod (EventInfo ei)
1587 if (ei is MyEventBuilder) {
1588 Pair pair = (Pair) events [ei];
1590 return (MethodInfo) pair.Second;
1592 return ei.GetRemoveMethod ();
1595 static Hashtable priv_fields_events;
1597 static public bool RegisterPrivateFieldOfEvent (EventInfo einfo, FieldBuilder builder)
1599 if (priv_fields_events == null)
1600 priv_fields_events = new Hashtable ();
1602 if (priv_fields_events.Contains (einfo))
1605 priv_fields_events.Add (einfo, builder);
1610 static public MemberInfo GetPrivateFieldOfEvent (EventInfo ei)
1612 return (MemberInfo) priv_fields_events [ei];
1615 static Hashtable properties;
1617 static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set)
1619 if (properties == null)
1620 properties = new Hashtable ();
1622 if (properties.Contains (pb))
1625 properties.Add (pb, new Pair (get, set));
1630 static public bool RegisterIndexer (PropertyBuilder pb, MethodBase get, MethodBase set, Type[] args)
1632 if (!RegisterProperty (pb, get,set))
1635 indexer_arguments.Add (pb, args);
1641 /// Given an array of interface types, expand and eliminate repeated ocurrences
1642 /// of an interface.
1646 /// This expands in context like: IA; IB : IA; IC : IA, IB; the interface "IC" to
1649 public static Type [] ExpandInterfaces (Type [] base_interfaces)
1651 ArrayList new_ifaces = new ArrayList ();
1653 foreach (Type iface in base_interfaces){
1654 if (!new_ifaces.Contains (iface))
1655 new_ifaces.Add (iface);
1657 Type [] implementing = TypeManager.GetInterfaces (iface);
1659 foreach (Type imp in implementing){
1660 if (!new_ifaces.Contains (imp))
1661 new_ifaces.Add (imp);
1664 Type [] ret = new Type [new_ifaces.Count];
1665 new_ifaces.CopyTo (ret, 0);
1670 /// This function returns the interfaces in the type `t'. Works with
1671 /// both types and TypeBuilders.
1673 public static Type [] GetInterfaces (Type t)
1676 // The reason for catching the Array case is that Reflection.Emit
1677 // will not return a TypeBuilder for Array types of TypeBuilder types,
1678 // but will still throw an exception if we try to call GetInterfaces
1681 // Since the array interfaces are always constant, we return those for
1686 t = TypeManager.array_type;
1688 if (t is TypeBuilder){
1689 Type [] parent_ifaces;
1691 if (t.BaseType == null)
1692 parent_ifaces = NoTypes;
1694 parent_ifaces = GetInterfaces (t.BaseType);
1695 Type [] type_ifaces = (Type []) builder_to_ifaces [t];
1696 if (type_ifaces == null)
1697 type_ifaces = NoTypes;
1699 int parent_count = parent_ifaces.Length;
1700 Type [] result = new Type [parent_count + type_ifaces.Length];
1701 parent_ifaces.CopyTo (result, 0);
1702 type_ifaces.CopyTo (result, parent_count);
1706 return t.GetInterfaces ();
1710 /// The following is used to check if a given type implements an interface.
1711 /// The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
1713 public static bool ImplementsInterface (Type t, Type iface)
1718 // FIXME OPTIMIZATION:
1719 // as soon as we hit a non-TypeBuiler in the interface
1720 // chain, we could return, as the `Type.GetInterfaces'
1721 // will return all the interfaces implement by the type
1725 interfaces = GetInterfaces (t);
1727 if (interfaces != null){
1728 foreach (Type i in interfaces){
1735 } while (t != null);
1740 // This is a custom version of Convert.ChangeType() which works
1741 // with the TypeBuilder defined types when compiling corlib.
1742 public static object ChangeType (object value, Type conversionType, out bool error)
1744 if (!(value is IConvertible)){
1749 IConvertible convertValue = (IConvertible) value;
1750 CultureInfo ci = CultureInfo.CurrentCulture;
1751 NumberFormatInfo provider = ci.NumberFormat;
1754 // We must use Type.Equals() here since `conversionType' is
1755 // the TypeBuilder created version of a system type and not
1756 // the system type itself. You cannot use Type.GetTypeCode()
1757 // on such a type - it'd always return TypeCode.Object.
1760 if (conversionType.Equals (typeof (Boolean)))
1761 return (object)(convertValue.ToBoolean (provider));
1762 else if (conversionType.Equals (typeof (Byte)))
1763 return (object)(convertValue.ToByte (provider));
1764 else if (conversionType.Equals (typeof (Char)))
1765 return (object)(convertValue.ToChar (provider));
1766 else if (conversionType.Equals (typeof (DateTime)))
1767 return (object)(convertValue.ToDateTime (provider));
1768 else if (conversionType.Equals (typeof (Decimal)))
1769 return (object)(convertValue.ToDecimal (provider));
1770 else if (conversionType.Equals (typeof (Double)))
1771 return (object)(convertValue.ToDouble (provider));
1772 else if (conversionType.Equals (typeof (Int16)))
1773 return (object)(convertValue.ToInt16 (provider));
1774 else if (conversionType.Equals (typeof (Int32)))
1775 return (object)(convertValue.ToInt32 (provider));
1776 else if (conversionType.Equals (typeof (Int64)))
1777 return (object)(convertValue.ToInt64 (provider));
1778 else if (conversionType.Equals (typeof (SByte)))
1779 return (object)(convertValue.ToSByte (provider));
1780 else if (conversionType.Equals (typeof (Single)))
1781 return (object)(convertValue.ToSingle (provider));
1782 else if (conversionType.Equals (typeof (String)))
1783 return (object)(convertValue.ToString (provider));
1784 else if (conversionType.Equals (typeof (UInt16)))
1785 return (object)(convertValue.ToUInt16 (provider));
1786 else if (conversionType.Equals (typeof (UInt32)))
1787 return (object)(convertValue.ToUInt32 (provider));
1788 else if (conversionType.Equals (typeof (UInt64)))
1789 return (object)(convertValue.ToUInt64 (provider));
1790 else if (conversionType.Equals (typeof (Object)))
1791 return (object)(value);
1798 // This is needed, because enumerations from assemblies
1799 // do not report their underlyingtype, but they report
1802 public static Type EnumToUnderlying (Type t)
1804 if (t == TypeManager.enum_type)
1807 t = t.UnderlyingSystemType;
1808 if (!TypeManager.IsEnumType (t))
1811 if (t is TypeBuilder) {
1812 // slow path needed to compile corlib
1813 if (t == TypeManager.bool_type ||
1814 t == TypeManager.byte_type ||
1815 t == TypeManager.sbyte_type ||
1816 t == TypeManager.char_type ||
1817 t == TypeManager.short_type ||
1818 t == TypeManager.ushort_type ||
1819 t == TypeManager.int32_type ||
1820 t == TypeManager.uint32_type ||
1821 t == TypeManager.int64_type ||
1822 t == TypeManager.uint64_type)
1824 throw new Exception ("Unhandled typecode in enum " + " from " + t.AssemblyQualifiedName);
1826 TypeCode tc = Type.GetTypeCode (t);
1829 case TypeCode.Boolean:
1830 return TypeManager.bool_type;
1832 return TypeManager.byte_type;
1833 case TypeCode.SByte:
1834 return TypeManager.sbyte_type;
1836 return TypeManager.char_type;
1837 case TypeCode.Int16:
1838 return TypeManager.short_type;
1839 case TypeCode.UInt16:
1840 return TypeManager.ushort_type;
1841 case TypeCode.Int32:
1842 return TypeManager.int32_type;
1843 case TypeCode.UInt32:
1844 return TypeManager.uint32_type;
1845 case TypeCode.Int64:
1846 return TypeManager.int64_type;
1847 case TypeCode.UInt64:
1848 return TypeManager.uint64_type;
1850 throw new Exception ("Unhandled typecode in enum " + tc + " from " + t.AssemblyQualifiedName);
1854 // When compiling corlib and called with one of the core types, return
1855 // the corresponding typebuilder for that type.
1857 public static Type TypeToCoreType (Type t)
1859 if (RootContext.StdLib || (t is TypeBuilder))
1862 TypeCode tc = Type.GetTypeCode (t);
1865 case TypeCode.Boolean:
1866 return TypeManager.bool_type;
1868 return TypeManager.byte_type;
1869 case TypeCode.SByte:
1870 return TypeManager.sbyte_type;
1872 return TypeManager.char_type;
1873 case TypeCode.Int16:
1874 return TypeManager.short_type;
1875 case TypeCode.UInt16:
1876 return TypeManager.ushort_type;
1877 case TypeCode.Int32:
1878 return TypeManager.int32_type;
1879 case TypeCode.UInt32:
1880 return TypeManager.uint32_type;
1881 case TypeCode.Int64:
1882 return TypeManager.int64_type;
1883 case TypeCode.UInt64:
1884 return TypeManager.uint64_type;
1885 case TypeCode.String:
1886 return TypeManager.string_type;
1888 if (t == typeof (void))
1889 return TypeManager.void_type;
1890 if (t == typeof (object))
1891 return TypeManager.object_type;
1892 if (t == typeof (System.Type))
1893 return TypeManager.type_type;
1899 /// Utility function that can be used to probe whether a type
1900 /// is managed or not.
1902 public static bool VerifyUnManaged (Type t, Location loc)
1904 if (t.IsValueType || t.IsPointer){
1906 // FIXME: this is more complex, we actually need to
1907 // make sure that the type does not contain any
1913 if (!RootContext.StdLib && (t == TypeManager.decimal_type))
1914 // We need this explicit check here to make it work when
1915 // compiling corlib.
1920 "Cannot take the address or size of a variable of a managed type ('" +
1921 CSharpName (t) + "')");
1926 /// Returns the name of the indexer in a given type.
1929 /// The default is not always `Item'. The user can change this behaviour by
1930 /// using the DefaultMemberAttribute in the class.
1932 /// For example, the String class indexer is named `Chars' not `Item'
1934 public static string IndexerPropertyName (Type t)
1936 if (t is TypeBuilder) {
1937 if (t.IsInterface) {
1938 Interface i = LookupInterface (t);
1940 if ((i == null) || (i.IndexerName == null))
1943 return i.IndexerName;
1945 TypeContainer tc = LookupTypeContainer (t);
1947 if ((tc == null) || (tc.IndexerName == null))
1950 return tc.IndexerName;
1954 System.Attribute attr = System.Attribute.GetCustomAttribute (
1955 t, TypeManager.default_member_type);
1957 DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
1958 return dma.MemberName;
1964 public static void MakePinned (LocalBuilder builder)
1967 // FIXME: Flag the "LocalBuilder" type as being
1968 // pinned. Figure out API.
1974 // Returns whether the array of memberinfos contains the given method
1976 static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method)
1978 Type [] new_args = TypeManager.GetArgumentTypes (new_method);
1980 foreach (MethodBase method in array){
1981 if (method.Name != new_method.Name)
1984 Type [] old_args = TypeManager.GetArgumentTypes (method);
1985 int old_count = old_args.Length;
1988 if (new_args.Length != old_count)
1991 for (i = 0; i < old_count; i++){
1992 if (old_args [i] != new_args [i])
2004 // We copy methods from `new_members' into `target_list' if the signature
2005 // for the method from in the new list does not exist in the target_list
2007 // The name is assumed to be the same.
2009 public static ArrayList CopyNewMethods (ArrayList target_list, MemberList new_members)
2011 if (target_list == null){
2012 target_list = new ArrayList ();
2014 foreach (MemberInfo mi in new_members){
2015 if (mi is MethodBase)
2016 target_list.Add (mi);
2021 MemberInfo [] target_array = new MemberInfo [target_list.Count];
2022 target_list.CopyTo (target_array, 0);
2024 foreach (MemberInfo mi in new_members){
2025 MethodBase new_method = (MethodBase) mi;
2027 if (!ArrayContainsMethod (target_array, new_method))
2028 target_list.Add (new_method);
2034 public enum MethodFlags {
2036 IsObsoleteError = 2,
2041 // Returns the TypeManager.MethodFlags for this method.
2042 // This emits an error 619 / warning 618 if the method is obsolete.
2043 // In the former case, TypeManager.MethodFlags.IsObsoleteError is returned.
2045 static public MethodFlags GetMethodFlags (MethodBase mb, Location loc)
2047 MethodFlags flags = 0;
2049 if (mb.DeclaringType is TypeBuilder){
2050 MethodData method = (MethodData) builder_to_method [mb];
2051 if (method == null) {
2052 // FIXME: implement Obsolete attribute on Property,
2053 // Indexer and Event.
2057 return method.GetMethodFlags (loc);
2060 object [] attrs = mb.GetCustomAttributes (true);
2061 foreach (object ta in attrs){
2062 if (!(ta is System.Attribute)){
2063 Console.WriteLine ("Unknown type in GetMethodFlags: " + ta);
2066 System.Attribute a = (System.Attribute) ta;
2067 if (a.TypeId == TypeManager.obsolete_attribute_type){
2068 ObsoleteAttribute oa = (ObsoleteAttribute) a;
2070 string method_desc = TypeManager.CSharpSignature (mb);
2073 Report.Error (619, loc, "Method `" + method_desc +
2074 "' is obsolete: `" + oa.Message + "'");
2075 return MethodFlags.IsObsoleteError;
2077 Report.Warning (618, loc, "Method `" + method_desc +
2078 "' is obsolete: `" + oa.Message + "'");
2080 flags |= MethodFlags.IsObsolete;
2086 // Skip over conditional code.
2088 if (a.TypeId == TypeManager.conditional_attribute_type){
2089 ConditionalAttribute ca = (ConditionalAttribute) a;
2091 if (RootContext.AllDefines [ca.ConditionString] == null)
2092 flags |= MethodFlags.ShouldIgnore;
2099 #region MemberLookup implementation
2102 // Name of the member
2104 static string closure_name;
2107 // Whether we allow private members in the result (since FindMembers
2108 // uses NonPublic for both protected and private), we need to distinguish.
2110 static bool closure_private_ok;
2113 // Who is invoking us and which type is being queried currently.
2115 static Type closure_invocation_type;
2116 static Type closure_queried_type;
2117 static Type closure_qualifier_type;
2120 // The assembly that defines the type is that is calling us
2122 static Assembly closure_invocation_assembly;
2125 // This filter filters by name + whether it is ok to include private
2126 // members in the search
2128 static internal bool FilterWithClosure (MemberInfo m, object filter_criteria)
2131 // Hack: we know that the filter criteria will always be in the `closure'
2135 if ((filter_criteria != null) && (m.Name != (string) filter_criteria))
2138 if (((closure_qualifier_type == null) || (closure_qualifier_type == closure_invocation_type)) &&
2139 (m.DeclaringType == closure_invocation_type))
2143 // Ugly: we need to find out the type of `m', and depending
2144 // on this, tell whether we accept or not
2146 if (m is MethodBase){
2147 MethodBase mb = (MethodBase) m;
2148 MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
2150 if (ma == MethodAttributes.Private)
2151 return closure_private_ok || (closure_invocation_type == m.DeclaringType);
2154 // FamAndAssem requires that we not only derivate, but we are on the
2157 if (ma == MethodAttributes.FamANDAssem){
2158 if (closure_invocation_assembly != mb.DeclaringType.Assembly)
2162 // Assembly and FamORAssem succeed if we're in the same assembly.
2163 if ((ma == MethodAttributes.Assembly) || (ma == MethodAttributes.FamORAssem)){
2164 if (closure_invocation_assembly == mb.DeclaringType.Assembly)
2168 // We already know that we aren't in the same assembly.
2169 if (ma == MethodAttributes.Assembly)
2172 // Family and FamANDAssem require that we derive.
2173 if ((ma == MethodAttributes.Family) || (ma == MethodAttributes.FamANDAssem)){
2174 if (closure_invocation_type == null)
2177 if (!IsSubclassOrNestedChildOf (closure_invocation_type, mb.DeclaringType))
2180 // Although a derived class can access protected members of its base class
2181 // it cannot do so through an instance of the base class (CS1540).
2182 if (!mb.IsStatic && (closure_invocation_type != closure_qualifier_type) &&
2183 (closure_qualifier_type != null) &&
2184 closure_invocation_type.IsSubclassOf (closure_qualifier_type))
2194 if (m is FieldInfo){
2195 FieldInfo fi = (FieldInfo) m;
2196 FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask;
2198 if (fa == FieldAttributes.Private)
2199 return closure_private_ok || (closure_invocation_type == m.DeclaringType);
2202 // FamAndAssem requires that we not only derivate, but we are on the
2205 if (fa == FieldAttributes.FamANDAssem){
2206 if (closure_invocation_assembly != fi.DeclaringType.Assembly)
2210 // Assembly and FamORAssem succeed if we're in the same assembly.
2211 if ((fa == FieldAttributes.Assembly) || (fa == FieldAttributes.FamORAssem)){
2212 if (closure_invocation_assembly == fi.DeclaringType.Assembly)
2216 // We already know that we aren't in the same assembly.
2217 if (fa == FieldAttributes.Assembly)
2220 // Family and FamANDAssem require that we derive.
2221 if ((fa == FieldAttributes.Family) || (fa == FieldAttributes.FamANDAssem)){
2222 if (closure_invocation_type == null)
2225 if (!IsSubclassOrNestedChildOf (closure_invocation_type, fi.DeclaringType))
2228 // Although a derived class can access protected members of its base class
2229 // it cannot do so through an instance of the base class (CS1540).
2230 if (!fi.IsStatic && (closure_invocation_type != closure_qualifier_type) &&
2231 (closure_qualifier_type != null) &&
2232 closure_invocation_type.IsSubclassOf (closure_qualifier_type))
2243 // EventInfos and PropertyInfos, return true because they lack permission
2244 // informaiton, so we need to check later on the methods.
2249 static MemberFilter FilterWithClosure_delegate = new MemberFilter (FilterWithClosure);
2252 // Looks up a member called `name' in the `queried_type'. This lookup
2253 // is done by code that is contained in the definition for `invocation_type'
2254 // through a qualifier of type `qualifier_type' (or null if there is no qualifier).
2256 // `invocation_type' is used to check whether we're allowed to access the requested
2257 // member wrt its protection level.
2259 // When called from MemberAccess, `qualifier_type' is the type which is used to access
2260 // the requested member (`class B { A a = new A (); a.foo = 5; }'; here invocation_type
2261 // is B and qualifier_type is A). This is used to do the CS1540 check.
2263 // When resolving a SimpleName, `qualifier_type' is null.
2265 // The `qualifier_type' is used for the CS1540 check; it's normally either null or
2266 // the same than `queried_type' - except when we're being called from BaseAccess;
2267 // in this case, `invocation_type' is the current type and `queried_type' the base
2268 // type, so this'd normally trigger a CS1540.
2270 // The binding flags are `bf' and the kind of members being looked up are `mt'
2272 // The return value always includes private members which code in `invocation_type'
2273 // is allowed to access (using the specified `qualifier_type' if given); only use
2274 // BindingFlags.NonPublic to bypass the permission check.
2276 // Returns an array of a single element for everything but Methods/Constructors
2277 // that might return multiple matches.
2279 public static MemberInfo [] MemberLookup (Type invocation_type, Type qualifier_type,
2280 Type queried_type, MemberTypes mt,
2281 BindingFlags original_bf, string name)
2283 Timer.StartTimer (TimerType.MemberLookup);
2285 MemberInfo[] retval = RealMemberLookup (invocation_type, qualifier_type,
2286 queried_type, mt, original_bf, name);
2288 Timer.StopTimer (TimerType.MemberLookup);
2293 static MemberInfo [] RealMemberLookup (Type invocation_type, Type qualifier_type,
2294 Type queried_type, MemberTypes mt,
2295 BindingFlags original_bf, string name)
2297 BindingFlags bf = original_bf;
2299 ArrayList method_list = null;
2300 Type current_type = queried_type;
2301 bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0;
2302 bool skip_iface_check = true, used_cache = false;
2303 bool always_ok_flag = false;
2305 closure_name = name;
2306 closure_invocation_type = invocation_type;
2307 closure_invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
2308 closure_qualifier_type = qualifier_type;
2311 // If we are a nested class, we always have access to our container
2314 if (invocation_type != null){
2315 string invocation_name = invocation_type.FullName;
2316 if (invocation_name.IndexOf ('+') != -1){
2317 string container = queried_type.FullName + "+";
2318 int container_length = container.Length;
2320 if (invocation_name.Length > container_length){
2321 string shared = invocation_name.Substring (0, container_length);
2323 if (shared == container)
2324 always_ok_flag = true;
2333 // `NonPublic' is lame, because it includes both protected and
2334 // private methods, so we need to control this behavior by
2335 // explicitly tracking if a private method is ok or not.
2337 // The possible cases are:
2338 // public, private and protected (internal does not come into the
2341 if ((invocation_type != null) &&
2342 ((invocation_type == current_type) ||
2343 IsNestedChildOf (invocation_type, current_type)) ||
2345 bf = original_bf | BindingFlags.NonPublic;
2349 closure_private_ok = (bf & BindingFlags.NonPublic) != 0;
2350 closure_queried_type = current_type;
2352 Timer.StopTimer (TimerType.MemberLookup);
2354 list = MemberLookup_FindMembers (current_type, mt, bf, name, out used_cache);
2356 Timer.StartTimer (TimerType.MemberLookup);
2359 // When queried for an interface type, the cache will automatically check all
2360 // inherited members, so we don't need to do this here. However, this only
2361 // works if we already used the cache in the first iteration of this loop.
2363 // If we used the cache in any further iteration, we can still terminate the
2364 // loop since the cache always looks in all parent classes.
2370 skip_iface_check = false;
2372 if (current_type == TypeManager.object_type)
2375 current_type = current_type.BaseType;
2378 // This happens with interfaces, they have a null
2379 // basetype. Look members up in the Object class.
2381 if (current_type == null)
2382 current_type = TypeManager.object_type;
2385 if (list.Count == 0)
2389 // Events and types are returned by both `static' and `instance'
2390 // searches, which means that our above FindMembers will
2391 // return two copies of the same.
2393 if (list.Count == 1 && !(list [0] is MethodBase)){
2394 return (MemberInfo []) list;
2398 // Multiple properties: we query those just to find out the indexer
2401 if (list [0] is PropertyInfo)
2402 return (MemberInfo []) list;
2405 // We found methods, turn the search into "method scan"
2409 method_list = CopyNewMethods (method_list, list);
2410 mt &= (MemberTypes.Method | MemberTypes.Constructor);
2411 } while (searching);
2413 if (method_list != null && method_list.Count > 0)
2414 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
2417 // This happens if we already used the cache in the first iteration, in this case
2418 // the cache already looked in all interfaces.
2420 if (skip_iface_check)
2424 // Interfaces do not list members they inherit, so we have to
2427 if (!queried_type.IsInterface)
2430 if (queried_type.IsArray)
2431 queried_type = TypeManager.array_type;
2433 Type [] ifaces = GetInterfaces (queried_type);
2437 foreach (Type itype in ifaces){
2440 x = MemberLookup (null, null, itype, mt, bf, name);
2452 /// There is exactly one instance of this class per type.
2454 public sealed class TypeHandle : IMemberContainer {
2455 public readonly TypeHandle BaseType;
2457 readonly int id = ++next_id;
2458 static int next_id = 0;
2461 /// Lookup a TypeHandle instance for the given type. If the type doesn't have
2462 /// a TypeHandle yet, a new instance of it is created. This static method
2463 /// ensures that we'll only have one TypeHandle instance per type.
2465 public static TypeHandle GetTypeHandle (Type t)
2467 TypeHandle handle = (TypeHandle) type_hash [t];
2471 handle = new TypeHandle (t);
2472 type_hash.Add (t, handle);
2477 /// Returns the TypeHandle for TypeManager.object_type.
2479 public static IMemberContainer ObjectType {
2481 if (object_type != null)
2484 object_type = GetTypeHandle (TypeManager.object_type);
2491 /// Returns the TypeHandle for TypeManager.array_type.
2493 public static IMemberContainer ArrayType {
2495 if (array_type != null)
2498 array_type = GetTypeHandle (TypeManager.array_type);
2504 private static PtrHashtable type_hash = new PtrHashtable ();
2506 private static TypeHandle object_type = null;
2507 private static TypeHandle array_type = null;
2510 private bool is_interface;
2511 private MemberCache member_cache;
2513 private TypeHandle (Type type)
2516 if (type.BaseType != null)
2517 BaseType = GetTypeHandle (type.BaseType);
2518 else if ((type != TypeManager.object_type) && (type != typeof (object)))
2519 is_interface = true;
2520 this.member_cache = new MemberCache (this);
2523 // IMemberContainer methods
2525 public string Name {
2527 return type.FullName;
2537 public IMemberContainer Parent {
2543 public bool IsInterface {
2545 return is_interface;
2549 public MemberList GetMembers (MemberTypes mt, BindingFlags bf)
2551 if (mt == MemberTypes.Event)
2552 return new MemberList (type.GetEvents (bf | BindingFlags.DeclaredOnly));
2554 return new MemberList (type.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
2558 // IMemberFinder methods
2560 public MemberList FindMembers (MemberTypes mt, BindingFlags bf, string name,
2561 MemberFilter filter, object criteria)
2563 return member_cache.FindMembers (mt, bf, name, filter, criteria);
2566 public MemberCache MemberCache {
2568 return member_cache;
2572 public override string ToString ()
2574 if (BaseType != null)
2575 return "TypeHandle (" + id + "," + Name + " : " + BaseType + ")";
2577 return "TypeHandle (" + id + "," + Name + ")";