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;
85 // An empty array of types
87 static public Type [] NoTypes;
91 // Expressions representing the internal types. Used during declaration
94 static public Expression system_object_expr, system_string_expr;
95 static public Expression system_boolean_expr, system_decimal_expr;
96 static public Expression system_single_expr, system_double_expr;
97 static public Expression system_sbyte_expr, system_byte_expr;
98 static public Expression system_int16_expr, system_uint16_expr;
99 static public Expression system_int32_expr, system_uint32_expr;
100 static public Expression system_int64_expr, system_uint64_expr;
101 static public Expression system_char_expr, system_void_expr;
102 static public Expression system_asynccallback_expr;
103 static public Expression system_iasyncresult_expr;
106 // This is only used when compiling corlib
108 static public Type system_int32_type;
109 static public Type system_array_type;
110 static public Type system_type_type;
111 static public Type system_assemblybuilder_type;
112 static public MethodInfo system_int_array_get_length;
113 static public MethodInfo system_int_array_get_rank;
114 static public MethodInfo system_object_array_clone;
115 static public MethodInfo system_int_array_get_length_int;
116 static public MethodInfo system_int_array_get_lower_bound_int;
117 static public MethodInfo system_int_array_get_upper_bound_int;
118 static public MethodInfo system_void_array_copyto_array_int;
119 static public MethodInfo system_void_set_corlib_type_builders;
123 // Internal, not really used outside
125 static Type runtime_helpers_type;
128 // These methods are called by code generated by the compiler
130 static public MethodInfo string_concat_string_string;
131 static public MethodInfo string_concat_string_string_string;
132 static public MethodInfo string_concat_string_string_string_string;
133 static public MethodInfo string_concat_object_object;
134 static public MethodInfo string_isinterneted_string;
135 static public MethodInfo system_type_get_type_from_handle;
136 static public MethodInfo object_getcurrent_void;
137 static public MethodInfo bool_movenext_void;
138 static public MethodInfo void_dispose_void;
139 static public MethodInfo void_monitor_enter_object;
140 static public MethodInfo void_monitor_exit_object;
141 static public MethodInfo void_initializearray_array_fieldhandle;
142 static public MethodInfo int_getlength_int;
143 static public MethodInfo delegate_combine_delegate_delegate;
144 static public MethodInfo delegate_remove_delegate_delegate;
145 static public MethodInfo int_get_offset_to_string_data;
146 static public MethodInfo int_array_get_length;
147 static public MethodInfo int_array_get_rank;
148 static public MethodInfo object_array_clone;
149 static public MethodInfo int_array_get_length_int;
150 static public MethodInfo int_array_get_lower_bound_int;
151 static public MethodInfo int_array_get_upper_bound_int;
152 static public MethodInfo void_array_copyto_array_int;
155 // The attribute constructors.
157 static public ConstructorInfo cons_param_array_attribute;
158 static public ConstructorInfo void_decimal_ctor_five_args;
159 static public ConstructorInfo unverifiable_code_ctor;
162 // Holds the Array of Assemblies that have been loaded
163 // (either because it is the default or the user used the
164 // -r command line option)
166 static Assembly [] assemblies;
169 // Keeps a list of module builders. We used this to do lookups
170 // on the modulebuilder using GetType -- needed for arrays
172 static ModuleBuilder [] modules;
175 // This is the type_cache from the assemblies to avoid
176 // hitting System.Reflection on every lookup.
178 static Hashtable types;
181 // This is used to hotld the corresponding TypeContainer objects
182 // since we need this in FindMembers
184 static Hashtable typecontainers;
187 // Keeps track of those types that are defined by the
190 static ArrayList user_types;
192 static PtrHashtable builder_to_declspace;
195 // Tracks the interfaces implemented by typebuilders. We only
196 // enter those who do implement or or more interfaces
198 static PtrHashtable builder_to_ifaces;
201 // Maps MethodBase.RuntimeTypeHandle to a Type array that contains
202 // the arguments to the method
204 static Hashtable method_arguments;
207 // Maps PropertyBuilder to a Type array that contains
208 // the arguments to the indexer
210 static Hashtable indexer_arguments;
213 // Maybe `method_arguments' should be replaced and only
214 // method_internal_params should be kept?
216 static Hashtable method_internal_params;
219 // Keeps track of attribute types
222 static Hashtable builder_to_attr;
225 // Keeps track of methods
228 static Hashtable builder_to_method;
236 /// A filter for Findmembers that uses the Signature object to
239 static bool SignatureFilter (MemberInfo mi, object criteria)
241 Signature sig = (Signature) criteria;
243 if (!(mi is MethodBase))
246 if (mi.Name != sig.name)
249 int count = sig.args.Length;
251 if (mi is MethodBuilder || mi is ConstructorBuilder){
252 Type [] candidate_args = GetArgumentTypes ((MethodBase) mi);
254 if (candidate_args.Length != count)
257 for (int i = 0; i < count; i++)
258 if (candidate_args [i] != sig.args [i])
263 ParameterInfo [] pars = ((MethodBase) mi).GetParameters ();
265 if (pars.Length != count)
268 for (int i = 0; i < count; i++)
269 if (pars [i].ParameterType != sig.args [i])
275 // A delegate that points to the filter above.
276 static MemberFilter signature_filter;
279 // These are expressions that represent some of the internal data types, used
282 static void InitExpressionTypes ()
284 system_object_expr = new TypeLookupExpression ("System.Object");
285 system_string_expr = new TypeLookupExpression ("System.String");
286 system_boolean_expr = new TypeLookupExpression ("System.Boolean");
287 system_decimal_expr = new TypeLookupExpression ("System.Decimal");
288 system_single_expr = new TypeLookupExpression ("System.Single");
289 system_double_expr = new TypeLookupExpression ("System.Double");
290 system_sbyte_expr = new TypeLookupExpression ("System.SByte");
291 system_byte_expr = new TypeLookupExpression ("System.Byte");
292 system_int16_expr = new TypeLookupExpression ("System.Int16");
293 system_uint16_expr = new TypeLookupExpression ("System.UInt16");
294 system_int32_expr = new TypeLookupExpression ("System.Int32");
295 system_uint32_expr = new TypeLookupExpression ("System.UInt32");
296 system_int64_expr = new TypeLookupExpression ("System.Int64");
297 system_uint64_expr = new TypeLookupExpression ("System.UInt64");
298 system_char_expr = new TypeLookupExpression ("System.Char");
299 system_void_expr = new TypeLookupExpression ("System.Void");
300 system_asynccallback_expr = new TypeLookupExpression ("System.AsyncCallback");
301 system_iasyncresult_expr = new TypeLookupExpression ("System.IAsyncResult");
304 static TypeManager ()
306 assemblies = new Assembly [0];
308 user_types = new ArrayList ();
310 types = new Hashtable ();
311 typecontainers = new Hashtable ();
313 builder_to_declspace = new PtrHashtable ();
314 builder_to_attr = new PtrHashtable ();
315 builder_to_method = new PtrHashtable ();
316 method_arguments = new PtrHashtable ();
317 method_internal_params = new PtrHashtable ();
318 indexer_arguments = new PtrHashtable ();
319 builder_to_ifaces = new PtrHashtable ();
321 NoTypes = new Type [0];
323 signature_filter = new MemberFilter (SignatureFilter);
324 InitExpressionTypes ();
327 public static void AddUserType (string name, TypeBuilder t, Type [] ifaces)
332 Type prev = (Type) types [name];
333 TypeContainer tc = builder_to_declspace [prev] as TypeContainer;
337 // This probably never happens, as we catch this before
339 Report.Error (-17, "The type `" + name + "' has already been defined.");
343 tc = builder_to_declspace [t] as TypeContainer;
346 1595, "The type `" + name + "' is defined in an existing assembly;"+
347 " Using the new definition from: " + tc.Location);
348 Report.Warning (1595, "Previously defined in: " + prev.Assembly.FullName);
356 builder_to_ifaces [t] = ifaces;
360 // This entry point is used by types that we define under the covers
362 public static void RegisterBuilder (TypeBuilder tb, Type [] ifaces)
365 builder_to_ifaces [tb] = ifaces;
368 public static void AddUserType (string name, TypeBuilder t, TypeContainer tc, Type [] ifaces)
370 builder_to_declspace.Add (t, tc);
371 typecontainers.Add (name, tc);
372 AddUserType (name, t, ifaces);
375 public static void AddDelegateType (string name, TypeBuilder t, Delegate del)
378 builder_to_declspace.Add (t, del);
381 public static void AddEnumType (string name, TypeBuilder t, Enum en)
384 builder_to_declspace.Add (t, en);
387 public static void AddUserInterface (string name, TypeBuilder t, Interface i, Type [] ifaces)
389 AddUserType (name, t, ifaces);
390 builder_to_declspace.Add (t, i);
393 public static void AddMethod (MethodBuilder builder, MethodData method)
395 builder_to_method.Add (builder, method);
398 public static void RegisterAttrType (Type t, TypeContainer tc)
400 builder_to_attr.Add (t, tc);
404 /// Returns the TypeContainer whose Type is `t' or null if there is no
405 /// TypeContainer for `t' (ie, the Type comes from a library)
407 public static TypeContainer LookupTypeContainer (Type t)
409 return builder_to_declspace [t] as TypeContainer;
412 public static IMemberContainer LookupMemberContainer (Type t)
414 if (t is TypeBuilder) {
415 IMemberContainer container = builder_to_declspace [t] as IMemberContainer;
416 if (container != null)
420 return TypeHandle.GetTypeHandle (t);
423 public static Interface LookupInterface (Type t)
425 return builder_to_declspace [t] as Interface;
428 public static Delegate LookupDelegate (Type t)
430 return builder_to_declspace [t] as Delegate;
433 public static Enum LookupEnum (Type t)
435 return builder_to_declspace [t] as Enum;
438 public static TypeContainer LookupAttr (Type t)
440 return (TypeContainer) builder_to_attr [t];
444 /// Registers an assembly to load types from.
446 public static void AddAssembly (Assembly a)
448 int top = assemblies.Length;
449 Assembly [] n = new Assembly [top + 1];
451 assemblies.CopyTo (n, 0);
458 /// Registers a module builder to lookup types from
460 public static void AddModule (ModuleBuilder mb)
462 int top = modules != null ? modules.Length : 0;
463 ModuleBuilder [] n = new ModuleBuilder [top + 1];
466 modules.CopyTo (n, 0);
472 // Low-level lookup, cache-less
474 static Type LookupTypeReflection (string name)
478 foreach (Assembly a in assemblies){
479 t = a.GetType (name);
484 foreach (ModuleBuilder mb in modules) {
485 t = mb.GetType (name);
493 static Hashtable negative_hits = new Hashtable ();
496 // This function is used when you want to avoid the lookups, and want to go
497 // directly to the source. This will use the cache.
499 // Notice that bypassing the cache is bad, because on Microsoft.NET runtime
500 // GetType ("DynamicType[]") != GetType ("DynamicType[]"), and there is no
501 // way to test things other than doing a fullname compare
503 public static Type LookupTypeDirect (string name)
505 Type t = (Type) types [name];
509 t = LookupTypeReflection (name);
518 /// Returns the Type associated with @name, takes care of the fact that
519 /// reflection expects nested types to be separated from the main type
520 /// with a "+" instead of a "."
522 public static Type LookupType (string name)
527 // First lookup in user defined and cached values
530 t = (Type) types [name];
535 if (negative_hits.Contains (name))
540 // Optimization: ComposedCast will work with an existing type, and might already have the
541 // full name of the type, so the full system lookup can probably be avoided.
544 string [] elements = name.Split ('.');
545 int count = elements.Length;
547 for (int n = 1; n <= count; n++){
548 string top_level_type = String.Join (".", elements, 0, n);
550 t = (Type) types [top_level_type];
552 t = LookupTypeReflection (top_level_type);
563 // We know that System.Object does not have children, and since its the parent of
564 // all the objects, it always gets probbed for inner classes.
566 if (top_level_type == "System.Object")
569 string newt = top_level_type + "+" + String.Join ("+", elements, n, count - n);
570 t = LookupTypeDirect (newt);
577 negative_hits [name] = true;
582 static Hashtable assemblies_namespaces = new Hashtable ();
585 // Returns a list of all namespaces in the assemblies and types loaded.
587 static Hashtable ExtractAssemblyNamespaces ()
589 foreach (Assembly a in assemblies){
590 foreach (Type t in a.GetTypes ()){
591 string ns = t.Namespace;
593 if (assemblies_namespaces.Contains (ns))
595 assemblies_namespaces [ns] = ns;
599 return assemblies_namespaces;
602 static Hashtable AddModuleNamespaces (Hashtable h)
604 foreach (ModuleBuilder mb in modules){
605 foreach (Type t in mb.GetTypes ()){
606 string ns = t.Namespace;
618 /// Returns the list of namespaces that are active for this executable
620 public static Hashtable GetAssemblyNamespaces (string executable_name)
622 string cache_name = executable_name + ".nsc";
623 Hashtable cached_namespaces = LoadCache (cache_name);
625 if (cached_namespaces != null)
626 assemblies_namespaces = cached_namespaces;
628 Console.WriteLine ("rebuilding namespace cache");
629 assemblies_namespaces = ExtractAssemblyNamespaces ();
630 SaveCache (cache_name);
633 return assemblies_namespaces;
636 public static Hashtable GetNamespaces ()
638 if (assemblies_namespaces == null)
639 assemblies_namespaces = ExtractAssemblyNamespaces ();
641 Hashtable nh = (Hashtable) assemblies_namespaces.Clone ();
643 return AddModuleNamespaces (nh);
647 // Loads the namespace cache for the given executable name
649 static Hashtable LoadCache (string cache_file)
651 if (!File.Exists (cache_file)){
652 Console.WriteLine ("Cache not found");
657 Hashtable cached_module_list, cached_namespaces;
659 using (FileStream fs = File.OpenRead (cache_file)){
660 StreamReader reader = new StreamReader (fs);
662 int assembly_count = Int32.Parse (reader.ReadLine ());
664 if (assembly_count != assemblies.Length){
665 Console.WriteLine ("Assembly missmatch ({0}, {1})", assembly_count, assemblies.Length);
669 int namespace_count = Int32.Parse (reader.ReadLine ());
671 cached_module_list = new Hashtable (assembly_count);
672 for (int i = 0; i < assembly_count; i++)
673 cached_module_list [reader.ReadLine ()] = true;
675 cached_namespaces = new Hashtable (namespace_count);
676 for (int i = 0; i < namespace_count; i++){
677 string s = reader.ReadLine ();
678 cached_namespaces [s] = s;
683 // Now, check that the cache is still valid
686 foreach (Assembly a in assemblies)
687 if (cached_module_list [a.CodeBase] == null){
688 Console.WriteLine ("assembly not found in cache: " + a.CodeBase);
692 return cached_namespaces;
698 static void SaveCache (string cache_file)
701 using (FileStream fs = File.OpenWrite (cache_file)){
702 StreamWriter writer = new StreamWriter (fs);
704 writer.WriteLine (assemblies.Length);
705 writer.WriteLine (assemblies_namespaces.Count);
707 foreach (Assembly a in assemblies)
708 writer.WriteLine (a.CodeBase);
710 foreach (DictionaryEntry de in assemblies_namespaces){
711 writer.WriteLine ((string) de.Key);
717 } catch (Exception e) {
718 Console.WriteLine ("Failed: " + e);
722 public static void GetAllTypes ()
724 Hashtable namespaces = new Hashtable ();
726 foreach (Assembly a in assemblies){
727 foreach (Type t in a.GetTypes ()){
731 foreach (ModuleBuilder mb in modules){
732 foreach (Type t in mb.GetTypes ()){
739 /// Returns the C# name of a type if possible, or the full type name otherwise
741 static public string CSharpName (Type t)
743 return Regex.Replace (t.FullName,
745 @"(Int32|UInt32|Int16|Uint16|Int64|UInt64|" +
746 @"Single|Double|Char|Decimal|Byte|SByte|Object|" +
747 @"Boolean|String|Void)" +
749 new MatchEvaluator (CSharpNameMatch));
752 static String CSharpNameMatch (Match match)
754 string s = match.Groups [1].Captures [0].Value;
756 Replace ("int32", "int").
757 Replace ("uint32", "uint").
758 Replace ("int16", "short").
759 Replace ("uint16", "ushort").
760 Replace ("int64", "long").
761 Replace ("uint64", "ulong").
762 Replace ("single", "float").
763 Replace ("boolean", "bool")
764 + match.Groups [2].Captures [0].Value;
768 /// Returns the signature of the method
770 static public string CSharpSignature (MethodBase mb)
775 // FIXME: We should really have a single function to do
776 // everything instead of the following 5 line pattern
778 ParameterData iparams = LookupParametersByBuilder (mb);
780 if (iparams == null){
781 ParameterInfo [] pi = mb.GetParameters ();
782 iparams = new ReflectionParameters (pi);
785 for (int i = 0; i < iparams.Count; i++) {
789 sig += iparams.ParameterDesc(i);
793 return mb.DeclaringType.Name + "." + mb.Name + sig;
797 /// Looks up a type, and aborts if it is not found. This is used
798 /// by types required by the compiler
800 static Type CoreLookupType (string name)
802 Type t = LookupType (name);
805 Report.Error (518, "The predefined type `" + name + "' is not defined or imported");
806 Environment.Exit (0);
813 /// Returns the MethodInfo for a method named `name' defined
814 /// in type `t' which takes arguments of types `args'
816 static MethodInfo GetMethod (Type t, string name, Type [] args)
824 list = FindMembers (t, MemberTypes.Method, instance_and_static | BindingFlags.Public,
825 signature_filter, sig);
826 if (list.Count == 0) {
827 Report.Error (-19, "Can not find the core function `" + name + "'");
831 MethodInfo mi = list [0] as MethodInfo;
833 Report.Error (-19, "Can not find the core function `" + name + "'");
841 /// Returns the ConstructorInfo for "args"
843 static ConstructorInfo GetConstructor (Type t, Type [] args)
851 list = FindMembers (t, MemberTypes.Constructor,
852 instance_and_static | BindingFlags.Public | BindingFlags.DeclaredOnly,
853 signature_filter, sig);
854 if (list.Count == 0){
855 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
859 ConstructorInfo ci = list [0] as ConstructorInfo;
861 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
868 public static void InitEnumUnderlyingTypes ()
871 int32_type = CoreLookupType ("System.Int32");
872 int64_type = CoreLookupType ("System.Int64");
873 uint32_type = CoreLookupType ("System.UInt32");
874 uint64_type = CoreLookupType ("System.UInt64");
875 byte_type = CoreLookupType ("System.Byte");
876 sbyte_type = CoreLookupType ("System.SByte");
877 short_type = CoreLookupType ("System.Int16");
878 ushort_type = CoreLookupType ("System.UInt16");
882 /// The types have to be initialized after the initial
883 /// population of the type has happened (for example, to
884 /// bootstrap the corlib.dll
886 public static void InitCoreTypes ()
888 object_type = CoreLookupType ("System.Object");
889 value_type = CoreLookupType ("System.ValueType");
891 InitEnumUnderlyingTypes ();
893 char_type = CoreLookupType ("System.Char");
894 string_type = CoreLookupType ("System.String");
895 float_type = CoreLookupType ("System.Single");
896 double_type = CoreLookupType ("System.Double");
897 char_ptr_type = CoreLookupType ("System.Char*");
898 decimal_type = CoreLookupType ("System.Decimal");
899 bool_type = CoreLookupType ("System.Boolean");
900 enum_type = CoreLookupType ("System.Enum");
902 multicast_delegate_type = CoreLookupType ("System.MulticastDelegate");
903 delegate_type = CoreLookupType ("System.Delegate");
905 array_type = CoreLookupType ("System.Array");
906 void_type = CoreLookupType ("System.Void");
907 type_type = CoreLookupType ("System.Type");
909 runtime_field_handle_type = CoreLookupType ("System.RuntimeFieldHandle");
910 runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices.RuntimeHelpers");
911 default_member_type = CoreLookupType ("System.Reflection.DefaultMemberAttribute");
912 runtime_handle_type = CoreLookupType ("System.RuntimeTypeHandle");
913 asynccallback_type = CoreLookupType ("System.AsyncCallback");
914 iasyncresult_type = CoreLookupType ("System.IAsyncResult");
915 ienumerator_type = CoreLookupType ("System.Collections.IEnumerator");
916 idisposable_type = CoreLookupType ("System.IDisposable");
917 icloneable_type = CoreLookupType ("System.ICloneable");
918 monitor_type = CoreLookupType ("System.Threading.Monitor");
919 intptr_type = CoreLookupType ("System.IntPtr");
921 attribute_type = CoreLookupType ("System.Attribute");
922 attribute_usage_type = CoreLookupType ("System.AttributeUsageAttribute");
923 dllimport_type = CoreLookupType ("System.Runtime.InteropServices.DllImportAttribute");
924 methodimpl_attr_type = CoreLookupType ("System.Runtime.CompilerServices.MethodImplAttribute");
925 marshal_as_attr_type = CoreLookupType ("System.Runtime.InteropServices.MarshalAsAttribute");
926 param_array_type = CoreLookupType ("System.ParamArrayAttribute");
929 // Temporary while people upgrade their corlibs
932 // Change from LookupType to CoreLookupType before release
934 guid_attr_type = LookupType ("System.Runtime.InteropServices.GuidAttribute");
936 unverifiable_code_type= CoreLookupType ("System.Security.UnverifiableCodeAttribute");
938 void_ptr_type = CoreLookupType ("System.Void*");
940 indexer_name_type = CoreLookupType ("System.Runtime.CompilerServices.IndexerNameAttribute");
942 exception_type = CoreLookupType ("System.Exception");
947 obsolete_attribute_type = CoreLookupType ("System.ObsoleteAttribute");
948 conditional_attribute_type = CoreLookupType ("System.Diagnostics.ConditionalAttribute");
951 // When compiling corlib, store the "real" types here.
953 if (!RootContext.StdLib) {
954 system_int32_type = typeof (System.Int32);
955 system_array_type = typeof (System.Array);
956 system_type_type = typeof (System.Type);
957 system_assemblybuilder_type = typeof (System.Reflection.Emit.AssemblyBuilder);
959 Type [] void_arg = { };
960 system_int_array_get_length = GetMethod (
961 system_array_type, "get_Length", void_arg);
962 system_int_array_get_rank = GetMethod (
963 system_array_type, "get_Rank", void_arg);
964 system_object_array_clone = GetMethod (
965 system_array_type, "Clone", void_arg);
967 Type [] system_int_arg = { system_int32_type };
968 system_int_array_get_length_int = GetMethod (
969 system_array_type, "GetLength", system_int_arg);
970 system_int_array_get_upper_bound_int = GetMethod (
971 system_array_type, "GetUpperBound", system_int_arg);
972 system_int_array_get_lower_bound_int = GetMethod (
973 system_array_type, "GetLowerBound", system_int_arg);
975 Type [] system_array_int_arg = { system_array_type, system_int32_type };
976 system_void_array_copyto_array_int = GetMethod (
977 system_array_type, "CopyTo", system_array_int_arg);
979 Type [] system_type_type_arg = { system_type_type, system_type_type, system_type_type };
982 system_void_set_corlib_type_builders = GetMethod (
983 system_assemblybuilder_type, "SetCorlibTypeBuilders",
984 system_type_type_arg);
986 object[] args = new object [3];
987 args [0] = object_type;
988 args [1] = value_type;
989 args [2] = enum_type;
991 system_void_set_corlib_type_builders.Invoke (CodeGen.AssemblyBuilder, args);
993 Console.WriteLine ("Corlib compilation is not supported in Microsoft.NET due to bugs in it");
999 // The helper methods that are used by the compiler
1001 public static void InitCodeHelpers ()
1004 // Now load the default methods that we use.
1006 Type [] string_string = { string_type, string_type };
1007 string_concat_string_string = GetMethod (
1008 string_type, "Concat", string_string);
1009 Type [] string_string_string = { string_type, string_type, string_type };
1010 string_concat_string_string_string = GetMethod (
1011 string_type, "Concat", string_string_string);
1012 Type [] string_string_string_string = { string_type, string_type, string_type, string_type };
1013 string_concat_string_string_string_string = GetMethod (
1014 string_type, "Concat", string_string_string_string);
1016 Type [] object_object = { object_type, object_type };
1017 string_concat_object_object = GetMethod (
1018 string_type, "Concat", object_object);
1020 Type [] string_ = { string_type };
1021 string_isinterneted_string = GetMethod (
1022 string_type, "IsInterned", string_);
1024 Type [] runtime_type_handle = { runtime_handle_type };
1025 system_type_get_type_from_handle = GetMethod (
1026 type_type, "GetTypeFromHandle", runtime_type_handle);
1028 Type [] delegate_delegate = { delegate_type, delegate_type };
1029 delegate_combine_delegate_delegate = GetMethod (
1030 delegate_type, "Combine", delegate_delegate);
1032 delegate_remove_delegate_delegate = GetMethod (
1033 delegate_type, "Remove", delegate_delegate);
1038 Type [] void_arg = { };
1039 object_getcurrent_void = GetMethod (
1040 ienumerator_type, "get_Current", void_arg);
1041 bool_movenext_void = GetMethod (
1042 ienumerator_type, "MoveNext", void_arg);
1043 void_dispose_void = GetMethod (
1044 idisposable_type, "Dispose", void_arg);
1045 int_get_offset_to_string_data = GetMethod (
1046 runtime_helpers_type, "get_OffsetToStringData", void_arg);
1047 int_array_get_length = GetMethod (
1048 array_type, "get_Length", void_arg);
1049 int_array_get_rank = GetMethod (
1050 array_type, "get_Rank", void_arg);
1055 Type [] int_arg = { int32_type };
1056 int_array_get_length_int = GetMethod (
1057 array_type, "GetLength", int_arg);
1058 int_array_get_upper_bound_int = GetMethod (
1059 array_type, "GetUpperBound", int_arg);
1060 int_array_get_lower_bound_int = GetMethod (
1061 array_type, "GetLowerBound", int_arg);
1064 // System.Array methods
1066 object_array_clone = GetMethod (
1067 array_type, "Clone", void_arg);
1068 Type [] array_int_arg = { array_type, int32_type };
1069 void_array_copyto_array_int = GetMethod (
1070 array_type, "CopyTo", array_int_arg);
1075 Type [] object_arg = { object_type };
1076 void_monitor_enter_object = GetMethod (
1077 monitor_type, "Enter", object_arg);
1078 void_monitor_exit_object = GetMethod (
1079 monitor_type, "Exit", object_arg);
1081 Type [] array_field_handle_arg = { array_type, runtime_field_handle_type };
1083 void_initializearray_array_fieldhandle = GetMethod (
1084 runtime_helpers_type, "InitializeArray", array_field_handle_arg);
1089 int_getlength_int = GetMethod (
1090 array_type, "GetLength", int_arg);
1093 // Decimal constructors
1095 Type [] dec_arg = { int32_type, int32_type, int32_type, bool_type, byte_type };
1096 void_decimal_ctor_five_args = GetConstructor (
1097 decimal_type, dec_arg);
1102 cons_param_array_attribute = GetConstructor (
1103 param_array_type, void_arg);
1105 unverifiable_code_ctor = GetConstructor (
1106 unverifiable_code_type, void_arg);
1110 const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance;
1112 static Hashtable type_hash = new Hashtable ();
1115 /// This is the "old", non-cache based FindMembers() function. We cannot use
1116 /// the cache here because there is no member name argument.
1118 public static MemberList FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1119 MemberFilter filter, object criteria)
1121 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
1124 // `builder_to_declspace' contains all dynamic types.
1128 Timer.StartTimer (TimerType.FindMembers);
1129 list = decl.FindMembers (mt, bf, filter, criteria);
1130 Timer.StopTimer (TimerType.FindMembers);
1135 // We have to take care of arrays specially, because GetType on
1136 // a TypeBuilder array will return a Type, not a TypeBuilder,
1137 // and we can not call FindMembers on this type.
1139 if (t.IsSubclassOf (TypeManager.array_type))
1140 return new MemberList (TypeManager.array_type.FindMembers (mt, bf, filter, criteria));
1143 // Since FindMembers will not lookup both static and instance
1144 // members, we emulate this behaviour here.
1146 if ((bf & instance_and_static) == instance_and_static){
1147 MemberInfo [] i_members = t.FindMembers (
1148 mt, bf & ~BindingFlags.Static, filter, criteria);
1150 int i_len = i_members.Length;
1152 MemberInfo one = i_members [0];
1155 // If any of these are present, we are done!
1157 if ((one is Type) || (one is EventInfo) || (one is FieldInfo))
1158 return new MemberList (i_members);
1161 MemberInfo [] s_members = t.FindMembers (
1162 mt, bf & ~BindingFlags.Instance, filter, criteria);
1164 int s_len = s_members.Length;
1165 if (i_len > 0 || s_len > 0)
1166 return new MemberList (i_members, s_members);
1169 return new MemberList (i_members);
1171 return new MemberList (s_members);
1175 return new MemberList (t.FindMembers (mt, bf, filter, criteria));
1180 /// This method is only called from within MemberLookup. It tries to use the member
1181 /// cache if possible and falls back to the normal FindMembers if not. The `used_cache'
1182 /// flag tells the caller whether we used the cache or not. If we used the cache, then
1183 /// our return value will already contain all inherited members and the caller don't need
1184 /// to check base classes and interfaces anymore.
1186 private static MemberList MemberLookup_FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1187 string name, out bool used_cache)
1190 // We have to take care of arrays specially, because GetType on
1191 // a TypeBuilder array will return a Type, not a TypeBuilder,
1192 // and we can not call FindMembers on this type.
1194 if (t.IsSubclassOf (TypeManager.array_type)) {
1196 return TypeHandle.ArrayType.MemberCache.FindMembers (
1197 mt, bf, name, FilterWithClosure_delegate, null);
1201 // If this is a dynamic type, it's always in the `builder_to_declspace' hash table
1202 // and we can ask the DeclSpace for the MemberCache.
1204 if (t is TypeBuilder) {
1205 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
1206 MemberCache cache = decl.MemberCache;
1209 // If this DeclSpace has a MemberCache, use it.
1212 if (cache != null) {
1214 return cache.FindMembers (
1215 mt, bf, name, FilterWithClosure_delegate, null);
1218 // If there is no MemberCache, we need to use the "normal" FindMembers.
1221 Timer.StartTimer (TimerType.FindMembers);
1222 list = decl.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
1223 FilterWithClosure_delegate, name);
1224 Timer.StopTimer (TimerType.FindMembers);
1230 // This call will always succeed. There is exactly one TypeHandle instance per
1231 // type, TypeHandle.GetTypeHandle() will either return it or create a new one
1232 // if it didn't already exist.
1234 TypeHandle handle = TypeHandle.GetTypeHandle (t);
1237 return handle.MemberCache.FindMembers (mt, bf, name, FilterWithClosure_delegate, null);
1240 public static bool IsBuiltinType (Type t)
1242 if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
1243 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1244 t == char_type || t == short_type || t == decimal_type || t == bool_type ||
1245 t == sbyte_type || t == byte_type || t == ushort_type || t == void_type)
1252 // This is like IsBuiltinType, but lacks decimal_type, we should also clean up
1253 // the pieces in the code where we use IsBuiltinType and special case decimal_type.
1255 public static bool IsCLRType (Type t)
1257 if (t == object_type || t == int32_type || t == uint32_type ||
1258 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1259 t == char_type || t == short_type || t == bool_type ||
1260 t == sbyte_type || t == byte_type || t == ushort_type)
1266 public static bool IsDelegateType (Type t)
1268 if (t.IsSubclassOf (TypeManager.delegate_type))
1274 public static bool IsEnumType (Type t)
1276 if (t.IsSubclassOf (TypeManager.enum_type))
1283 // Whether a type is unmanaged. This is used by the unsafe code (25.2)
1285 public static bool IsUnmanagedType (Type t)
1287 if (IsBuiltinType (t) && t != TypeManager.string_type)
1296 if (IsValueType (t)){
1297 if (t is TypeBuilder){
1298 TypeContainer tc = LookupTypeContainer (t);
1300 foreach (Field f in tc.Fields){
1301 if (f.FieldBuilder.IsStatic)
1303 if (!IsUnmanagedType (f.FieldBuilder.FieldType))
1307 FieldInfo [] fields = t.GetFields ();
1309 foreach (FieldInfo f in fields){
1312 if (!IsUnmanagedType (f.FieldType))
1322 public static bool IsValueType (Type t)
1324 if (t.IsSubclassOf (TypeManager.value_type))
1330 public static bool IsInterfaceType (Type t)
1332 Interface iface = builder_to_declspace [t] as Interface;
1341 // Checks whether `type' is a subclass or nested child of `parent'.
1343 public static bool IsSubclassOrNestedChildOf (Type type, Type parent)
1346 if ((type == parent) || type.IsSubclassOf (parent))
1349 // Handle nested types.
1350 type = type.DeclaringType;
1351 } while (type != null);
1357 // Checks whether `type' is a nested child of `parent'.
1359 public static bool IsNestedChildOf (Type type, Type parent)
1361 if ((type == parent) || type.IsSubclassOf (parent))
1364 return IsSubclassOrNestedChildOf (type, parent);
1368 /// Returns the User Defined Types
1370 public static ArrayList UserTypes {
1376 public static Hashtable TypeContainers {
1378 return typecontainers;
1382 static Hashtable attr_to_allowmult;
1384 public static void RegisterAttributeAllowMultiple (Type attr_type, bool allow)
1386 if (attr_to_allowmult == null)
1387 attr_to_allowmult = new PtrHashtable ();
1389 if (attr_to_allowmult.Contains (attr_type))
1392 attr_to_allowmult.Add (attr_type, allow);
1396 public static bool AreMultipleAllowed (Type attr_type)
1398 if (!(attr_type is TypeBuilder)) {
1399 System.Attribute [] attrs = System.Attribute.GetCustomAttributes (attr_type);
1401 foreach (System.Attribute tmp in attrs)
1402 if (tmp is AttributeUsageAttribute)
1403 return ((AttributeUsageAttribute) tmp).AllowMultiple;
1408 if (attr_to_allowmult == null)
1411 return (bool) attr_to_allowmult [attr_type];
1414 static Hashtable builder_to_constant;
1416 public static void RegisterConstant (FieldBuilder fb, Const c)
1418 if (builder_to_constant == null)
1419 builder_to_constant = new PtrHashtable ();
1421 if (builder_to_constant.Contains (fb))
1424 builder_to_constant.Add (fb, c);
1427 public static Const LookupConstant (FieldBuilder fb)
1429 if (builder_to_constant == null)
1432 return (Const) builder_to_constant [fb];
1436 /// Gigantic work around for missing features in System.Reflection.Emit follows.
1440 /// Since System.Reflection.Emit can not return MethodBase.GetParameters
1441 /// for anything which is dynamic, and we need this in a number of places,
1442 /// we register this information here, and use it afterwards.
1444 static public bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] args)
1449 method_arguments.Add (mb, args);
1450 method_internal_params.Add (mb, ip);
1455 static public InternalParameters LookupParametersByBuilder (MethodBase mb)
1457 if (! (mb is ConstructorBuilder || mb is MethodBuilder))
1460 if (method_internal_params.Contains (mb))
1461 return (InternalParameters) method_internal_params [mb];
1463 throw new Exception ("Argument for Method not registered" + mb);
1467 /// Returns the argument types for a method based on its methodbase
1469 /// For dynamic methods, we use the compiler provided types, for
1470 /// methods from existing assemblies we load them from GetParameters,
1471 /// and insert them into the cache
1473 static public Type [] GetArgumentTypes (MethodBase mb)
1475 if (method_arguments.Contains (mb))
1476 return (Type []) method_arguments [mb];
1478 ParameterInfo [] pi = mb.GetParameters ();
1480 Type [] types = new Type [c];
1482 for (int i = 0; i < c; i++)
1483 types [i] = pi [i].ParameterType;
1485 method_arguments.Add (mb, types);
1491 /// Returns the argument types for an indexer based on its PropertyInfo
1493 /// For dynamic indexers, we use the compiler provided types, for
1494 /// indexers from existing assemblies we load them from GetParameters,
1495 /// and insert them into the cache
1497 static public Type [] GetArgumentTypes (PropertyInfo indexer)
1499 if (indexer_arguments.Contains (indexer))
1500 return (Type []) indexer_arguments [indexer];
1501 else if (indexer is PropertyBuilder)
1502 // If we're a PropertyBuilder and not in the
1503 // `indexer_arguments' hash, then we're a property and
1507 ParameterInfo [] pi = indexer.GetIndexParameters ();
1508 // Property, not an indexer.
1512 Type [] types = new Type [c];
1514 for (int i = 0; i < c; i++)
1515 types [i] = pi [i].ParameterType;
1517 indexer_arguments.Add (indexer, types);
1523 // This is a workaround the fact that GetValue is not
1524 // supported for dynamic types
1526 static Hashtable fields = new Hashtable ();
1527 static public bool RegisterFieldValue (FieldBuilder fb, object value)
1529 if (fields.Contains (fb))
1532 fields.Add (fb, value);
1537 static public object GetValue (FieldBuilder fb)
1542 static Hashtable fieldbuilders_to_fields = new Hashtable ();
1543 static public bool RegisterFieldBase (FieldBuilder fb, FieldBase f)
1545 if (fieldbuilders_to_fields.Contains (fb))
1548 fieldbuilders_to_fields.Add (fb, f);
1552 static public FieldBase GetField (FieldInfo fb)
1554 return (FieldBase) fieldbuilders_to_fields [fb];
1557 static Hashtable events;
1559 static public bool RegisterEvent (MyEventBuilder eb, MethodBase add, MethodBase remove)
1562 events = new Hashtable ();
1564 if (events.Contains (eb))
1567 events.Add (eb, new Pair (add, remove));
1572 static public MethodInfo GetAddMethod (EventInfo ei)
1574 if (ei is MyEventBuilder) {
1575 Pair pair = (Pair) events [ei];
1577 return (MethodInfo) pair.First;
1579 return ei.GetAddMethod ();
1582 static public MethodInfo GetRemoveMethod (EventInfo ei)
1584 if (ei is MyEventBuilder) {
1585 Pair pair = (Pair) events [ei];
1587 return (MethodInfo) pair.Second;
1589 return ei.GetAddMethod ();
1592 static Hashtable priv_fields_events;
1594 static public bool RegisterPrivateFieldOfEvent (EventInfo einfo, FieldBuilder builder)
1596 if (priv_fields_events == null)
1597 priv_fields_events = new Hashtable ();
1599 if (priv_fields_events.Contains (einfo))
1602 priv_fields_events.Add (einfo, builder);
1607 static public MemberInfo GetPrivateFieldOfEvent (EventInfo ei)
1609 return (MemberInfo) priv_fields_events [ei];
1612 static Hashtable properties;
1614 static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set)
1616 if (properties == null)
1617 properties = new Hashtable ();
1619 if (properties.Contains (pb))
1622 properties.Add (pb, new Pair (get, set));
1627 static public bool RegisterIndexer (PropertyBuilder pb, MethodBase get, MethodBase set, Type[] args)
1629 if (!RegisterProperty (pb, get,set))
1632 indexer_arguments.Add (pb, args);
1638 /// Given an array of interface types, expand and eliminate repeated ocurrences
1639 /// of an interface.
1643 /// This expands in context like: IA; IB : IA; IC : IA, IB; the interface "IC" to
1646 public static Type [] ExpandInterfaces (Type [] base_interfaces)
1648 ArrayList new_ifaces = new ArrayList ();
1650 foreach (Type iface in base_interfaces){
1651 if (!new_ifaces.Contains (iface))
1652 new_ifaces.Add (iface);
1654 Type [] implementing = TypeManager.GetInterfaces (iface);
1656 foreach (Type imp in implementing){
1657 if (!new_ifaces.Contains (imp))
1658 new_ifaces.Add (imp);
1661 Type [] ret = new Type [new_ifaces.Count];
1662 new_ifaces.CopyTo (ret, 0);
1667 /// This function returns the interfaces in the type `t'. Works with
1668 /// both types and TypeBuilders.
1670 public static Type [] GetInterfaces (Type t)
1673 // The reason for catching the Array case is that Reflection.Emit
1674 // will not return a TypeBuilder for Array types of TypeBuilder types,
1675 // but will still throw an exception if we try to call GetInterfaces
1678 // Since the array interfaces are always constant, we return those for
1683 t = TypeManager.array_type;
1685 if (t is TypeBuilder){
1686 Type [] parent_ifaces;
1688 if (t.BaseType == null)
1689 parent_ifaces = NoTypes;
1691 parent_ifaces = GetInterfaces (t.BaseType);
1692 Type [] type_ifaces = (Type []) builder_to_ifaces [t];
1693 if (type_ifaces == null)
1694 type_ifaces = NoTypes;
1696 int parent_count = parent_ifaces.Length;
1697 Type [] result = new Type [parent_count + type_ifaces.Length];
1698 parent_ifaces.CopyTo (result, 0);
1699 type_ifaces.CopyTo (result, parent_count);
1703 return t.GetInterfaces ();
1707 /// The following is used to check if a given type implements an interface.
1708 /// The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
1710 public static bool ImplementsInterface (Type t, Type iface)
1715 // FIXME OPTIMIZATION:
1716 // as soon as we hit a non-TypeBuiler in the interface
1717 // chain, we could return, as the `Type.GetInterfaces'
1718 // will return all the interfaces implement by the type
1722 interfaces = GetInterfaces (t);
1724 if (interfaces != null){
1725 foreach (Type i in interfaces){
1732 } while (t != null);
1737 // This is a custom version of Convert.ChangeType() which works
1738 // with the TypeBuilder defined types when compiling corlib.
1739 public static object ChangeType (object value, Type conversionType)
1741 if (!(value is IConvertible))
1742 throw new ArgumentException ();
1744 IConvertible convertValue = (IConvertible) value;
1745 CultureInfo ci = CultureInfo.CurrentCulture;
1746 NumberFormatInfo provider = ci.NumberFormat;
1749 // We must use Type.Equals() here since `conversionType' is
1750 // the TypeBuilder created version of a system type and not
1751 // the system type itself. You cannot use Type.GetTypeCode()
1752 // on such a type - it'd always return TypeCode.Object.
1754 if (conversionType.Equals (typeof (Boolean)))
1755 return (object)(convertValue.ToBoolean (provider));
1756 else if (conversionType.Equals (typeof (Byte)))
1757 return (object)(convertValue.ToByte (provider));
1758 else if (conversionType.Equals (typeof (Char)))
1759 return (object)(convertValue.ToChar (provider));
1760 else if (conversionType.Equals (typeof (DateTime)))
1761 return (object)(convertValue.ToDateTime (provider));
1762 else if (conversionType.Equals (typeof (Decimal)))
1763 return (object)(convertValue.ToDecimal (provider));
1764 else if (conversionType.Equals (typeof (Double)))
1765 return (object)(convertValue.ToDouble (provider));
1766 else if (conversionType.Equals (typeof (Int16)))
1767 return (object)(convertValue.ToInt16 (provider));
1768 else if (conversionType.Equals (typeof (Int32)))
1769 return (object)(convertValue.ToInt32 (provider));
1770 else if (conversionType.Equals (typeof (Int64)))
1771 return (object)(convertValue.ToInt64 (provider));
1772 else if (conversionType.Equals (typeof (SByte)))
1773 return (object)(convertValue.ToSByte (provider));
1774 else if (conversionType.Equals (typeof (Single)))
1775 return (object)(convertValue.ToSingle (provider));
1776 else if (conversionType.Equals (typeof (String)))
1777 return (object)(convertValue.ToString (provider));
1778 else if (conversionType.Equals (typeof (UInt16)))
1779 return (object)(convertValue.ToUInt16 (provider));
1780 else if (conversionType.Equals (typeof (UInt32)))
1781 return (object)(convertValue.ToUInt32 (provider));
1782 else if (conversionType.Equals (typeof (UInt64)))
1783 return (object)(convertValue.ToUInt64 (provider));
1784 else if (conversionType.Equals (typeof (Object)))
1785 return (object)(value);
1787 throw new InvalidCastException ();
1791 // This is needed, because enumerations from assemblies
1792 // do not report their underlyingtype, but they report
1795 public static Type EnumToUnderlying (Type t)
1797 if (t == TypeManager.enum_type)
1800 t = t.UnderlyingSystemType;
1801 if (!TypeManager.IsEnumType (t))
1804 if (t is TypeBuilder) {
1805 // slow path needed to compile corlib
1806 if (t == TypeManager.bool_type ||
1807 t == TypeManager.byte_type ||
1808 t == TypeManager.sbyte_type ||
1809 t == TypeManager.char_type ||
1810 t == TypeManager.short_type ||
1811 t == TypeManager.ushort_type ||
1812 t == TypeManager.int32_type ||
1813 t == TypeManager.uint32_type ||
1814 t == TypeManager.int64_type ||
1815 t == TypeManager.uint64_type)
1817 throw new Exception ("Unhandled typecode in enum " + " from " + t.AssemblyQualifiedName);
1819 TypeCode tc = Type.GetTypeCode (t);
1822 case TypeCode.Boolean:
1823 return TypeManager.bool_type;
1825 return TypeManager.byte_type;
1826 case TypeCode.SByte:
1827 return TypeManager.sbyte_type;
1829 return TypeManager.char_type;
1830 case TypeCode.Int16:
1831 return TypeManager.short_type;
1832 case TypeCode.UInt16:
1833 return TypeManager.ushort_type;
1834 case TypeCode.Int32:
1835 return TypeManager.int32_type;
1836 case TypeCode.UInt32:
1837 return TypeManager.uint32_type;
1838 case TypeCode.Int64:
1839 return TypeManager.int64_type;
1840 case TypeCode.UInt64:
1841 return TypeManager.uint64_type;
1843 throw new Exception ("Unhandled typecode in enum " + tc + " from " + t.AssemblyQualifiedName);
1847 // When compiling corlib and called with one of the core types, return
1848 // the corresponding typebuilder for that type.
1850 public static Type TypeToCoreType (Type t)
1852 if (RootContext.StdLib || (t is TypeBuilder))
1855 TypeCode tc = Type.GetTypeCode (t);
1858 case TypeCode.Boolean:
1859 return TypeManager.bool_type;
1861 return TypeManager.byte_type;
1862 case TypeCode.SByte:
1863 return TypeManager.sbyte_type;
1865 return TypeManager.char_type;
1866 case TypeCode.Int16:
1867 return TypeManager.short_type;
1868 case TypeCode.UInt16:
1869 return TypeManager.ushort_type;
1870 case TypeCode.Int32:
1871 return TypeManager.int32_type;
1872 case TypeCode.UInt32:
1873 return TypeManager.uint32_type;
1874 case TypeCode.Int64:
1875 return TypeManager.int64_type;
1876 case TypeCode.UInt64:
1877 return TypeManager.uint64_type;
1878 case TypeCode.String:
1879 return TypeManager.string_type;
1881 if (t == typeof (void))
1882 return TypeManager.void_type;
1883 if (t == typeof (object))
1884 return TypeManager.object_type;
1885 if (t == typeof (System.Type))
1886 return TypeManager.type_type;
1892 /// Utility function that can be used to probe whether a type
1893 /// is managed or not.
1895 public static bool VerifyUnManaged (Type t, Location loc)
1897 if (t.IsValueType || t.IsPointer){
1899 // FIXME: this is more complex, we actually need to
1900 // make sure that the type does not contain any
1906 if (!RootContext.StdLib && (t == TypeManager.decimal_type))
1907 // We need this explicit check here to make it work when
1908 // compiling corlib.
1913 "Cannot take the address or size of a variable of a managed type ('" +
1914 CSharpName (t) + "')");
1919 /// Returns the name of the indexer in a given type.
1922 /// The default is not always `Item'. The user can change this behaviour by
1923 /// using the DefaultMemberAttribute in the class.
1925 /// For example, the String class indexer is named `Chars' not `Item'
1927 public static string IndexerPropertyName (Type t)
1929 if (t is TypeBuilder) {
1930 if (t.IsInterface) {
1931 Interface i = LookupInterface (t);
1933 if ((i == null) || (i.IndexerName == null))
1936 return i.IndexerName;
1938 TypeContainer tc = LookupTypeContainer (t);
1940 if ((tc == null) || (tc.IndexerName == null))
1943 return tc.IndexerName;
1947 System.Attribute attr = System.Attribute.GetCustomAttribute (
1948 t, TypeManager.default_member_type);
1950 DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
1951 return dma.MemberName;
1957 public static void MakePinned (LocalBuilder builder)
1960 // FIXME: Flag the "LocalBuilder" type as being
1961 // pinned. Figure out API.
1967 // Returns whether the array of memberinfos contains the given method
1969 static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method)
1971 Type [] new_args = TypeManager.GetArgumentTypes (new_method);
1973 foreach (MethodBase method in array){
1974 if (method.Name != new_method.Name)
1977 Type [] old_args = TypeManager.GetArgumentTypes (method);
1978 int old_count = old_args.Length;
1981 if (new_args.Length != old_count)
1984 for (i = 0; i < old_count; i++){
1985 if (old_args [i] != new_args [i])
1997 // We copy methods from `new_members' into `target_list' if the signature
1998 // for the method from in the new list does not exist in the target_list
2000 // The name is assumed to be the same.
2002 public static ArrayList CopyNewMethods (ArrayList target_list, MemberList new_members)
2004 if (target_list == null){
2005 target_list = new ArrayList ();
2007 foreach (MemberInfo mi in new_members){
2008 if (mi is MethodBase)
2009 target_list.Add (mi);
2014 MemberInfo [] target_array = new MemberInfo [target_list.Count];
2015 target_list.CopyTo (target_array, 0);
2017 foreach (MemberInfo mi in new_members){
2018 MethodBase new_method = (MethodBase) mi;
2020 if (!ArrayContainsMethod (target_array, new_method))
2021 target_list.Add (new_method);
2027 public enum MethodFlags {
2029 IsObsoleteError = 2,
2034 // Returns the TypeManager.MethodFlags for this method.
2035 // This emits an error 619 / warning 618 if the method is obsolete.
2036 // In the former case, TypeManager.MethodFlags.IsObsoleteError is returned.
2038 static public MethodFlags GetMethodFlags (MethodBase mb, Location loc)
2040 MethodFlags flags = 0;
2042 if (mb.DeclaringType is TypeBuilder){
2043 MethodData method = (MethodData) builder_to_method [mb];
2044 if (method == null) {
2045 // FIXME: implement Obsolete attribute on Property,
2046 // Indexer and Event.
2050 return method.GetMethodFlags (loc);
2053 object [] attrs = mb.GetCustomAttributes (true);
2054 foreach (object ta in attrs){
2055 if (!(ta is System.Attribute)){
2056 Console.WriteLine ("Unknown type in GetMethodFlags: " + ta);
2059 System.Attribute a = (System.Attribute) ta;
2060 if (a.TypeId == TypeManager.obsolete_attribute_type){
2061 ObsoleteAttribute oa = (ObsoleteAttribute) a;
2063 string method_desc = TypeManager.CSharpSignature (mb);
2066 Report.Error (619, loc, "Method `" + method_desc +
2067 "' is obsolete: `" + oa.Message + "'");
2068 return MethodFlags.IsObsoleteError;
2070 Report.Warning (618, loc, "Method `" + method_desc +
2071 "' is obsolete: `" + oa.Message + "'");
2073 flags |= MethodFlags.IsObsolete;
2079 // Skip over conditional code.
2081 if (a.TypeId == TypeManager.conditional_attribute_type){
2082 ConditionalAttribute ca = (ConditionalAttribute) a;
2084 if (RootContext.AllDefines [ca.ConditionString] == null)
2085 flags |= MethodFlags.ShouldIgnore;
2092 #region MemberLookup implementation
2095 // Name of the member
2097 static string closure_name;
2100 // Whether we allow private members in the result (since FindMembers
2101 // uses NonPublic for both protected and private), we need to distinguish.
2103 static bool closure_private_ok;
2106 // Who is invoking us and which type is being queried currently.
2108 static Type closure_invocation_type;
2109 static Type closure_queried_type;
2110 static Type closure_qualifier_type;
2113 // The assembly that defines the type is that is calling us
2115 static Assembly closure_invocation_assembly;
2118 // This filter filters by name + whether it is ok to include private
2119 // members in the search
2121 static internal bool FilterWithClosure (MemberInfo m, object filter_criteria)
2124 // Hack: we know that the filter criteria will always be in the `closure'
2128 if ((filter_criteria != null) && (m.Name != (string) filter_criteria))
2131 if (((closure_qualifier_type == null) || (closure_qualifier_type == closure_invocation_type)) &&
2132 (m.DeclaringType == closure_invocation_type))
2136 // Ugly: we need to find out the type of `m', and depending
2137 // on this, tell whether we accept or not
2139 if (m is MethodBase){
2140 MethodBase mb = (MethodBase) m;
2141 MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
2143 if (ma == MethodAttributes.Private)
2144 return closure_private_ok || (closure_invocation_type == m.DeclaringType);
2147 // FamAndAssem requires that we not only derivate, but we are on the
2150 if (ma == MethodAttributes.FamANDAssem){
2151 if (closure_invocation_assembly != mb.DeclaringType.Assembly)
2155 // Assembly and FamORAssem succeed if we're in the same assembly.
2156 if ((ma == MethodAttributes.Assembly) || (ma == MethodAttributes.FamORAssem)){
2157 if (closure_invocation_assembly == mb.DeclaringType.Assembly)
2161 // We already know that we aren't in the same assembly.
2162 if (ma == MethodAttributes.Assembly)
2165 // Family and FamANDAssem require that we derive.
2166 if ((ma == MethodAttributes.Family) || (ma == MethodAttributes.FamANDAssem)){
2167 if (closure_invocation_type == null)
2170 if (!IsSubclassOrNestedChildOf (closure_invocation_type, mb.DeclaringType))
2173 // Although a derived class can access protected members of its base class
2174 // it cannot do so through an instance of the base class (CS1540).
2175 if (!mb.IsStatic && (closure_invocation_type != closure_qualifier_type) &&
2176 (closure_qualifier_type != null) &&
2177 closure_invocation_type.IsSubclassOf (closure_qualifier_type))
2187 if (m is FieldInfo){
2188 FieldInfo fi = (FieldInfo) m;
2189 FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask;
2191 if (fa == FieldAttributes.Private)
2192 return closure_private_ok || (closure_invocation_type == m.DeclaringType);
2195 // FamAndAssem requires that we not only derivate, but we are on the
2198 if (fa == FieldAttributes.FamANDAssem){
2199 if (closure_invocation_assembly != fi.DeclaringType.Assembly)
2203 // Assembly and FamORAssem succeed if we're in the same assembly.
2204 if ((fa == FieldAttributes.Assembly) || (fa == FieldAttributes.FamORAssem)){
2205 if (closure_invocation_assembly == fi.DeclaringType.Assembly)
2209 // We already know that we aren't in the same assembly.
2210 if (fa == FieldAttributes.Assembly)
2213 // Family and FamANDAssem require that we derive.
2214 if ((fa == FieldAttributes.Family) || (fa == FieldAttributes.FamANDAssem)){
2215 if (closure_invocation_type == null)
2218 if (!IsSubclassOrNestedChildOf (closure_invocation_type, fi.DeclaringType))
2221 // Although a derived class can access protected members of its base class
2222 // it cannot do so through an instance of the base class (CS1540).
2223 if (!fi.IsStatic && (closure_invocation_type != closure_qualifier_type) &&
2224 (closure_qualifier_type != null) &&
2225 closure_invocation_type.IsSubclassOf (closure_qualifier_type))
2236 // EventInfos and PropertyInfos, return true because they lack permission
2237 // informaiton, so we need to check later on the methods.
2242 static MemberFilter FilterWithClosure_delegate = new MemberFilter (FilterWithClosure);
2245 // Looks up a member called `name' in the `queried_type'. This lookup
2246 // is done by code that is contained in the definition for `invocation_type'
2247 // through a qualifier of type `qualifier_type' (or null if there is no qualifier).
2249 // `invocation_type' is used to check whether we're allowed to access the requested
2250 // member wrt its protection level.
2252 // When called from MemberAccess, `qualifier_type' is the type which is used to access
2253 // the requested member (`class B { A a = new A (); a.foo = 5; }'; here invocation_type
2254 // is B and qualifier_type is A). This is used to do the CS1540 check.
2256 // When resolving a SimpleName, `qualifier_type' is null.
2258 // The `qualifier_type' is used for the CS1540 check; it's normally either null or
2259 // the same than `queried_type' - except when we're being called from BaseAccess;
2260 // in this case, `invocation_type' is the current type and `queried_type' the base
2261 // type, so this'd normally trigger a CS1540.
2263 // The binding flags are `bf' and the kind of members being looked up are `mt'
2265 // The return value always includes private members which code in `invocation_type'
2266 // is allowed to access (using the specified `qualifier_type' if given); only use
2267 // BindingFlags.NonPublic to bypass the permission check.
2269 // Returns an array of a single element for everything but Methods/Constructors
2270 // that might return multiple matches.
2272 public static MemberInfo [] MemberLookup (Type invocation_type, Type qualifier_type,
2273 Type queried_type, MemberTypes mt,
2274 BindingFlags original_bf, string name)
2276 Timer.StartTimer (TimerType.MemberLookup);
2278 MemberInfo[] retval = RealMemberLookup (invocation_type, qualifier_type,
2279 queried_type, mt, original_bf, name);
2281 Timer.StopTimer (TimerType.MemberLookup);
2286 static MemberInfo [] RealMemberLookup (Type invocation_type, Type qualifier_type,
2287 Type queried_type, MemberTypes mt,
2288 BindingFlags original_bf, string name)
2290 BindingFlags bf = original_bf;
2292 ArrayList method_list = null;
2293 Type current_type = queried_type;
2294 bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0;
2295 bool skip_iface_check = true, used_cache = false;
2296 bool always_ok_flag = false;
2298 closure_name = name;
2299 closure_invocation_type = invocation_type;
2300 closure_invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
2301 closure_qualifier_type = qualifier_type;
2304 // If we are a nested class, we always have access to our container
2307 if (invocation_type != null){
2308 string invocation_name = invocation_type.FullName;
2309 if (invocation_name.IndexOf ('+') != -1){
2310 string container = queried_type.FullName + "+";
2311 int container_length = container.Length;
2313 if (invocation_name.Length > container_length){
2314 string shared = invocation_name.Substring (0, container_length);
2316 if (shared == container)
2317 always_ok_flag = true;
2326 // `NonPublic' is lame, because it includes both protected and
2327 // private methods, so we need to control this behavior by
2328 // explicitly tracking if a private method is ok or not.
2330 // The possible cases are:
2331 // public, private and protected (internal does not come into the
2334 if ((invocation_type != null) &&
2335 ((invocation_type == current_type) ||
2336 IsNestedChildOf (invocation_type, current_type)) ||
2338 bf = original_bf | BindingFlags.NonPublic;
2342 closure_private_ok = (bf & BindingFlags.NonPublic) != 0;
2343 closure_queried_type = current_type;
2345 Timer.StopTimer (TimerType.MemberLookup);
2347 list = MemberLookup_FindMembers (current_type, mt, bf, name, out used_cache);
2349 Timer.StartTimer (TimerType.MemberLookup);
2352 // When queried for an interface type, the cache will automatically check all
2353 // inherited members, so we don't need to do this here. However, this only
2354 // works if we already used the cache in the first iteration of this loop.
2356 // If we used the cache in any further iteration, we can still terminate the
2357 // loop since the cache always looks in all parent classes.
2363 skip_iface_check = false;
2365 if (current_type == TypeManager.object_type)
2368 current_type = current_type.BaseType;
2371 // This happens with interfaces, they have a null
2372 // basetype. Look members up in the Object class.
2374 if (current_type == null)
2375 current_type = TypeManager.object_type;
2378 if (list.Count == 0)
2382 // Events and types are returned by both `static' and `instance'
2383 // searches, which means that our above FindMembers will
2384 // return two copies of the same.
2386 if (list.Count == 1 && !(list [0] is MethodBase)){
2387 return (MemberInfo []) list;
2391 // Multiple properties: we query those just to find out the indexer
2394 if (list [0] is PropertyInfo)
2395 return (MemberInfo []) list;
2398 // We found methods, turn the search into "method scan"
2402 method_list = CopyNewMethods (method_list, list);
2403 mt &= (MemberTypes.Method | MemberTypes.Constructor);
2404 } while (searching);
2406 if (method_list != null && method_list.Count > 0)
2407 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
2410 // This happens if we already used the cache in the first iteration, in this case
2411 // the cache already looked in all interfaces.
2413 if (skip_iface_check)
2417 // Interfaces do not list members they inherit, so we have to
2420 if (!queried_type.IsInterface)
2423 if (queried_type.IsArray)
2424 queried_type = TypeManager.array_type;
2426 Type [] ifaces = GetInterfaces (queried_type);
2430 foreach (Type itype in ifaces){
2433 x = MemberLookup (null, null, itype, mt, bf, name);
2445 /// There is exactly one instance of this class per type.
2447 public sealed class TypeHandle : IMemberContainer {
2448 public readonly TypeHandle BaseType;
2450 readonly int id = ++next_id;
2451 static int next_id = 0;
2454 /// Lookup a TypeHandle instance for the given type. If the type doesn't have
2455 /// a TypeHandle yet, a new instance of it is created. This static method
2456 /// ensures that we'll only have one TypeHandle instance per type.
2458 public static TypeHandle GetTypeHandle (Type t)
2460 TypeHandle handle = (TypeHandle) type_hash [t];
2464 handle = new TypeHandle (t);
2465 type_hash.Add (t, handle);
2470 /// Returns the TypeHandle for TypeManager.object_type.
2472 public static IMemberContainer ObjectType {
2474 if (object_type != null)
2477 object_type = GetTypeHandle (TypeManager.object_type);
2484 /// Returns the TypeHandle for TypeManager.array_type.
2486 public static IMemberContainer ArrayType {
2488 if (array_type != null)
2491 array_type = GetTypeHandle (TypeManager.array_type);
2497 private static PtrHashtable type_hash = new PtrHashtable ();
2499 private static TypeHandle object_type = null;
2500 private static TypeHandle array_type = null;
2503 private bool is_interface;
2504 private MemberCache member_cache;
2506 private TypeHandle (Type type)
2509 if (type.BaseType != null)
2510 BaseType = GetTypeHandle (type.BaseType);
2511 else if ((type != TypeManager.object_type) && (type != typeof (object)))
2512 is_interface = true;
2513 this.member_cache = new MemberCache (this);
2516 // IMemberContainer methods
2518 public string Name {
2520 return type.FullName;
2530 public IMemberContainer Parent {
2536 public bool IsInterface {
2538 return is_interface;
2542 public MemberList GetMembers (MemberTypes mt, BindingFlags bf)
2544 if (mt == MemberTypes.Event)
2545 return new MemberList (type.GetEvents (bf | BindingFlags.DeclaredOnly));
2547 return new MemberList (type.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
2551 // IMemberFinder methods
2553 public MemberList FindMembers (MemberTypes mt, BindingFlags bf, string name,
2554 MemberFilter filter, object criteria)
2556 return member_cache.FindMembers (mt, bf, name, filter, criteria);
2559 public MemberCache MemberCache {
2561 return member_cache;
2565 public override string ToString ()
2567 if (BaseType != null)
2568 return "TypeHandle (" + id + "," + Name + " : " + BaseType + ")";
2570 return "TypeHandle (" + id + "," + Name + ")";