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;
27 using System.Text.RegularExpressions;
28 using System.Runtime.CompilerServices;
29 using System.Diagnostics;
31 namespace Mono.CSharp {
33 public class TypeManager {
35 // A list of core types that the compiler requires or uses
37 static public Type object_type;
38 static public Type value_type;
39 static public Type string_type;
40 static public Type int32_type;
41 static public Type uint32_type;
42 static public Type int64_type;
43 static public Type uint64_type;
44 static public Type float_type;
45 static public Type double_type;
46 static public Type char_type;
47 static public Type char_ptr_type;
48 static public Type short_type;
49 static public Type decimal_type;
50 static public Type bool_type;
51 static public Type sbyte_type;
52 static public Type byte_type;
53 static public Type ushort_type;
54 static public Type enum_type;
55 static public Type delegate_type;
56 static public Type multicast_delegate_type;
57 static public Type void_type;
58 static public Type enumeration_type;
59 static public Type array_type;
60 static public Type runtime_handle_type;
61 static public Type icloneable_type;
62 static public Type type_type;
63 static public Type ienumerator_type;
64 static public Type ienumerable_type;
65 static public Type idisposable_type;
66 static public Type iconvertible_type;
67 static public Type default_member_type;
68 static public Type iasyncresult_type;
69 static public Type asynccallback_type;
70 static public Type intptr_type;
71 static public Type monitor_type;
72 static public Type runtime_field_handle_type;
73 static public Type runtime_argument_handle_type;
74 static public Type attribute_type;
75 static public Type attribute_usage_type;
76 static public Type dllimport_type;
77 static public Type unverifiable_code_type;
78 static public Type methodimpl_attr_type;
79 static public Type marshal_as_attr_type;
80 static public Type new_constraint_attr_type;
81 static public Type param_array_type;
82 static public Type guid_attr_type;
83 static public Type void_ptr_type;
84 static public Type indexer_name_type;
85 static public Type exception_type;
86 static public Type activator_type;
87 static public Type invalid_operation_exception_type;
88 static public Type not_supported_exception_type;
89 static public Type obsolete_attribute_type;
90 static public Type conditional_attribute_type;
91 static public Type in_attribute_type;
92 static public Type cls_compliant_attribute_type;
93 static public Type typed_reference_type;
94 static public Type arg_iterator_type;
95 static public Type mbr_type;
96 static public Type struct_layout_attribute_type;
97 static public Type field_offset_attribute_type;
99 static public Type generic_ienumerator_type;
100 static public Type generic_ienumerable_type;
103 // An empty array of types
105 static public Type [] NoTypes;
106 static public TypeExpr [] NoTypeExprs;
110 // Expressions representing the internal types. Used during declaration
113 static public TypeExpr system_object_expr, system_string_expr;
114 static public TypeExpr system_boolean_expr, system_decimal_expr;
115 static public TypeExpr system_single_expr, system_double_expr;
116 static public TypeExpr system_sbyte_expr, system_byte_expr;
117 static public TypeExpr system_int16_expr, system_uint16_expr;
118 static public TypeExpr system_int32_expr, system_uint32_expr;
119 static public TypeExpr system_int64_expr, system_uint64_expr;
120 static public TypeExpr system_char_expr, system_void_expr;
121 static public TypeExpr system_asynccallback_expr;
122 static public TypeExpr system_iasyncresult_expr;
123 static public TypeExpr system_valuetype_expr;
124 static public TypeExpr system_intptr_expr;
127 // This is only used when compiling corlib
129 static public Type system_int32_type;
130 static public Type system_array_type;
131 static public Type system_type_type;
132 static public Type system_assemblybuilder_type;
133 static public MethodInfo system_int_array_get_length;
134 static public MethodInfo system_int_array_get_rank;
135 static public MethodInfo system_object_array_clone;
136 static public MethodInfo system_int_array_get_length_int;
137 static public MethodInfo system_int_array_get_lower_bound_int;
138 static public MethodInfo system_int_array_get_upper_bound_int;
139 static public MethodInfo system_void_array_copyto_array_int;
143 // Internal, not really used outside
145 static Type runtime_helpers_type;
148 // These methods are called by code generated by the compiler
150 static public MethodInfo string_concat_string_string;
151 static public MethodInfo string_concat_string_string_string;
152 static public MethodInfo string_concat_string_string_string_string;
153 static public MethodInfo string_concat_string_dot_dot_dot;
154 static public MethodInfo string_concat_object_object;
155 static public MethodInfo string_concat_object_object_object;
156 static public MethodInfo string_concat_object_dot_dot_dot;
157 static public MethodInfo string_isinterneted_string;
158 static public MethodInfo system_type_get_type_from_handle;
159 static public MethodInfo object_getcurrent_void;
160 static public MethodInfo bool_movenext_void;
161 static public MethodInfo ienumerable_getenumerator_void;
162 static public MethodInfo void_reset_void;
163 static public MethodInfo void_dispose_void;
164 static public MethodInfo void_monitor_enter_object;
165 static public MethodInfo void_monitor_exit_object;
166 static public MethodInfo void_initializearray_array_fieldhandle;
167 static public MethodInfo int_getlength_int;
168 static public MethodInfo delegate_combine_delegate_delegate;
169 static public MethodInfo delegate_remove_delegate_delegate;
170 static public MethodInfo int_get_offset_to_string_data;
171 static public MethodInfo int_array_get_length;
172 static public MethodInfo int_array_get_rank;
173 static public MethodInfo object_array_clone;
174 static public MethodInfo int_array_get_length_int;
175 static public MethodInfo int_array_get_lower_bound_int;
176 static public MethodInfo int_array_get_upper_bound_int;
177 static public MethodInfo void_array_copyto_array_int;
178 static public MethodInfo activator_create_instance;
181 // The attribute constructors.
183 static public ConstructorInfo object_ctor;
184 static public ConstructorInfo cons_param_array_attribute;
185 static public ConstructorInfo void_decimal_ctor_five_args;
186 static public ConstructorInfo unverifiable_code_ctor;
187 static public ConstructorInfo invalid_operation_ctor;
188 static public ConstructorInfo default_member_ctor;
191 // Holds the Array of Assemblies that have been loaded
192 // (either because it is the default or the user used the
193 // -r command line option)
195 static Assembly [] assemblies;
198 // Keeps a list of modules. We used this to do lookups
199 // on the module using GetType -- needed for arrays
201 static Module [] modules;
204 // This is the type_cache from the assemblies to avoid
205 // hitting System.Reflection on every lookup.
207 static Hashtable types;
210 // This is used to hotld the corresponding TypeContainer objects
211 // since we need this in FindMembers
213 static Hashtable typecontainers;
216 // Keeps track of those types that are defined by the
219 static ArrayList user_types;
221 static PtrHashtable builder_to_declspace;
224 // Tracks the interfaces implemented by typebuilders. We only
225 // enter those who do implement or or more interfaces
227 static PtrHashtable builder_to_ifaces;
230 // Tracks the generic parameters.
232 static PtrHashtable builder_to_type_param;
235 // Maps MethodBase.RuntimeTypeHandle to a Type array that contains
236 // the arguments to the method
238 static Hashtable method_arguments;
241 // Maps PropertyBuilder to a Type array that contains
242 // the arguments to the indexer
244 static Hashtable indexer_arguments;
247 // Maybe `method_arguments' should be replaced and only
248 // method_internal_params should be kept?
250 static Hashtable method_internal_params;
253 // Keeps track of methods
256 static Hashtable builder_to_method;
259 // Contains all public types from referenced assemblies.
260 // This member is used only if CLS Compliance verification is required.
262 public static Hashtable all_imported_types;
269 public static void CleanUp ()
271 // Lets get everything clean so that we can collect before generating code
275 typecontainers = null;
277 builder_to_declspace = null;
278 builder_to_ifaces = null;
279 method_arguments = null;
280 indexer_arguments = null;
281 method_internal_params = null;
282 builder_to_method = null;
283 builder_to_type_param = null;
287 negative_hits = null;
288 builder_to_constant = null;
289 fieldbuilders_to_fields = null;
291 priv_fields_events = null;
294 TypeHandle.CleanUp ();
298 /// A filter for Findmembers that uses the Signature object to
301 static bool SignatureFilter (MemberInfo mi, object criteria)
303 Signature sig = (Signature) criteria;
305 if (!(mi is MethodBase))
308 if (mi.Name != sig.name)
311 int count = sig.args.Length;
313 if (mi is MethodBuilder || mi is ConstructorBuilder){
314 Type [] candidate_args = GetArgumentTypes ((MethodBase) mi);
316 if (candidate_args.Length != count)
319 for (int i = 0; i < count; i++)
320 if (candidate_args [i] != sig.args [i])
325 ParameterInfo [] pars = ((MethodBase) mi).GetParameters ();
327 if (pars.Length != count)
330 for (int i = 0; i < count; i++)
331 if (pars [i].ParameterType != sig.args [i])
337 // A delegate that points to the filter above.
338 static MemberFilter signature_filter;
341 // These are expressions that represent some of the internal data types, used
344 static void InitExpressionTypes ()
346 system_object_expr = new TypeLookupExpression ("System.Object");
347 system_string_expr = new TypeLookupExpression ("System.String");
348 system_boolean_expr = new TypeLookupExpression ("System.Boolean");
349 system_decimal_expr = new TypeLookupExpression ("System.Decimal");
350 system_single_expr = new TypeLookupExpression ("System.Single");
351 system_double_expr = new TypeLookupExpression ("System.Double");
352 system_sbyte_expr = new TypeLookupExpression ("System.SByte");
353 system_byte_expr = new TypeLookupExpression ("System.Byte");
354 system_int16_expr = new TypeLookupExpression ("System.Int16");
355 system_uint16_expr = new TypeLookupExpression ("System.UInt16");
356 system_int32_expr = new TypeLookupExpression ("System.Int32");
357 system_uint32_expr = new TypeLookupExpression ("System.UInt32");
358 system_int64_expr = new TypeLookupExpression ("System.Int64");
359 system_uint64_expr = new TypeLookupExpression ("System.UInt64");
360 system_char_expr = new TypeLookupExpression ("System.Char");
361 system_void_expr = new TypeLookupExpression ("System.Void");
362 system_asynccallback_expr = new TypeLookupExpression ("System.AsyncCallback");
363 system_iasyncresult_expr = new TypeLookupExpression ("System.IAsyncResult");
364 system_valuetype_expr = new TypeLookupExpression ("System.ValueType");
365 system_intptr_expr = new TypeLookupExpression ("System.IntPtr");
368 static TypeManager ()
370 assemblies = new Assembly [0];
372 user_types = new ArrayList ();
374 types = new Hashtable ();
375 typecontainers = new Hashtable ();
377 builder_to_declspace = new PtrHashtable ();
378 builder_to_method = new PtrHashtable ();
379 method_arguments = new PtrHashtable ();
380 method_internal_params = new PtrHashtable ();
381 indexer_arguments = new PtrHashtable ();
382 builder_to_ifaces = new PtrHashtable ();
383 builder_to_type_param = new PtrHashtable ();
385 NoTypes = new Type [0];
386 NoTypeExprs = new TypeExpr [0];
388 signature_filter = new MemberFilter (SignatureFilter);
389 InitExpressionTypes ();
392 public static void HandleDuplicate (string name, Type t)
394 Type prev = (Type) types [name];
395 TypeContainer tc = builder_to_declspace [prev] as TypeContainer;
399 // This probably never happens, as we catch this before
401 Report.Error (-17, "The type `" + name + "' has already been defined.");
405 tc = builder_to_declspace [t] as TypeContainer;
408 1595, "The type `" + name + "' is defined in an existing assembly;"+
409 " Using the new definition from: " + tc.Location);
412 1595, "The type `" + name + "' is defined in an existing assembly;");
415 Report.Warning (1595, "Previously defined in: " + prev.Assembly.FullName);
421 public static void AddUserType (string name, TypeBuilder t)
426 HandleDuplicate (name, t);
432 // This entry point is used by types that we define under the covers
434 public static void RegisterBuilder (Type tb, Type [] ifaces)
437 builder_to_ifaces [tb] = ifaces;
440 public static void AddUserType (string name, TypeBuilder t, TypeContainer tc)
442 builder_to_declspace.Add (t, tc);
443 typecontainers.Add (name, tc);
444 AddUserType (name, t);
447 public static void AddDelegateType (string name, TypeBuilder t, Delegate del)
452 HandleDuplicate (name, t);
455 builder_to_declspace.Add (t, del);
458 public static void AddEnumType (string name, TypeBuilder t, Enum en)
463 HandleDuplicate (name, t);
465 builder_to_declspace.Add (t, en);
468 public static void AddMethod (MethodBase builder, IMethodData method)
470 builder_to_method.Add (builder, method);
473 public static IMethodData GetMethod (MethodBase builder)
475 return (IMethodData) builder_to_method [builder];
478 public static void AddTypeParameter (Type t, TypeParameter tparam)
480 if (!builder_to_type_param.Contains (t))
481 builder_to_type_param.Add (t, tparam);
485 /// Returns the DeclSpace whose Type is `t' or null if there is no
486 /// DeclSpace for `t' (ie, the Type comes from a library)
488 public static DeclSpace LookupDeclSpace (Type t)
490 return builder_to_declspace [t] as DeclSpace;
494 /// Returns the TypeContainer whose Type is `t' or null if there is no
495 /// TypeContainer for `t' (ie, the Type comes from a library)
497 public static TypeContainer LookupTypeContainer (Type t)
499 return builder_to_declspace [t] as TypeContainer;
502 public static TypeContainer LookupGenericTypeContainer (Type t)
504 while (t.IsGenericInstance)
505 t = t.GetGenericTypeDefinition ();
507 return LookupTypeContainer (t);
511 /// Fills member container from base interfaces
513 public static IMemberContainer LookupInterfaceContainer (Type[] types)
518 IMemberContainer complete = null;
519 foreach (Type t in types) {
520 IMemberContainer one_type_cont = null;
521 if (t is TypeBuilder) {
522 one_type_cont = builder_to_declspace [t] as IMemberContainer;
524 one_type_cont = TypeHandle.GetTypeHandle (t);
526 if (complete == null) {
527 complete = one_type_cont;
531 // We need to avoid including same member more than once
532 foreach (DictionaryEntry de in one_type_cont.MemberCache.Members) {
533 object o = complete.MemberCache.Members [de.Key];
535 complete.MemberCache.Members.Add (de.Key, de.Value);
539 ArrayList al_old = (ArrayList)o;
540 ArrayList al_new = (ArrayList)de.Value;
542 foreach (MemberCache.CacheEntry ce in al_new) {
544 foreach (MemberCache.CacheEntry ce_old in al_old) {
545 if (ce.Member == ce_old.Member) {
558 public static IMemberContainer LookupMemberContainer (Type t)
560 if (t is TypeBuilder) {
561 IMemberContainer container = builder_to_declspace [t] as IMemberContainer;
562 if (container != null)
566 if (t is GenericTypeParameterBuilder) {
567 IMemberContainer container = builder_to_type_param [t] as IMemberContainer;
569 if (container != null)
573 return TypeHandle.GetTypeHandle (t);
576 public static TypeContainer LookupInterface (Type t)
578 TypeContainer tc = (TypeContainer) builder_to_declspace [t];
579 if ((tc == null) || (tc.Kind != Kind.Interface))
585 public static Delegate LookupDelegate (Type t)
587 return builder_to_declspace [t] as Delegate;
590 public static Enum LookupEnum (Type t)
592 return builder_to_declspace [t] as Enum;
595 public static Class LookupClass (Type t)
597 return (Class) builder_to_declspace [t];
600 public static TypeParameter LookupTypeParameter (Type t)
602 return (TypeParameter) builder_to_type_param [t];
605 public static bool HasConstructorConstraint (Type t)
607 GenericConstraints gc = GetTypeParameterConstraints (t);
611 return (gc.Attributes & GenericParameterAttributes.DefaultConstructorConstraint) != 0;
614 public static GenericConstraints GetTypeParameterConstraints (Type t)
616 if (!t.IsGenericParameter)
617 throw new InvalidOperationException ();
619 TypeParameter tparam = LookupTypeParameter (t);
621 return tparam.GenericConstraints;
623 return new ReflectionConstraints (t);
627 /// Registers an assembly to load types from.
629 public static void AddAssembly (Assembly a)
631 foreach (Assembly assembly in assemblies) {
636 int top = assemblies.Length;
637 Assembly [] n = new Assembly [top + 1];
639 assemblies.CopyTo (n, 0);
645 public static Assembly [] GetAssemblies ()
651 /// Registers a module builder to lookup types from
653 public static void AddModule (Module mb)
655 int top = modules != null ? modules.Length : 0;
656 Module [] n = new Module [top + 1];
659 modules.CopyTo (n, 0);
664 public static Module[] Modules {
670 static Hashtable references = new Hashtable ();
673 // Gets the reference to T version of the Type (T&)
675 public static Type GetReferenceType (Type t)
677 return t.MakeByRefType ();
680 static Hashtable pointers = new Hashtable ();
683 // Gets the pointer to T version of the Type (T*)
685 public static Type GetPointerType (Type t)
687 string tname = t.FullName + "*";
689 Type ret = t.Assembly.GetType (tname);
692 // If the type comes from the assembly we are building
693 // We need the Hashtable, because .NET 1.1 will return different instance types
694 // every time we call ModuleBuilder.GetType.
697 if (pointers [t] == null)
698 pointers [t] = CodeGen.Module.Builder.GetType (tname);
700 ret = (Type) pointers [t];
707 // Low-level lookup, cache-less
709 static Type LookupTypeReflection (string name)
713 foreach (Assembly a in assemblies){
714 t = a.GetType (name);
719 TypeAttributes ta = t.Attributes & TypeAttributes.VisibilityMask;
720 if (ta == TypeAttributes.NotPublic ||
721 ta == TypeAttributes.NestedPrivate ||
722 ta == TypeAttributes.NestedAssembly ||
723 ta == TypeAttributes.NestedFamANDAssem){
726 // In .NET pointers turn out to be private, even if their
727 // element type is not
730 t = t.GetElementType ();
740 foreach (Module mb in modules) {
741 t = mb.GetType (name);
749 static Hashtable negative_hits = new Hashtable ();
752 // This function is used when you want to avoid the lookups, and want to go
753 // directly to the source. This will use the cache.
755 // Notice that bypassing the cache is bad, because on Microsoft.NET runtime
756 // GetType ("DynamicType[]") != GetType ("DynamicType[]"), and there is no
757 // way to test things other than doing a fullname compare
759 public static Type LookupTypeDirect (string name)
761 Type t = (Type) types [name];
765 t = LookupTypeReflection (name);
773 static readonly char [] dot_array = { '.' };
776 /// Returns the Type associated with @name, takes care of the fact that
777 /// reflection expects nested types to be separated from the main type
778 /// with a "+" instead of a "."
780 public static Type LookupType (string name)
785 // First lookup in user defined and cached values
788 t = (Type) types [name];
792 // Two thirds of the failures are caught here.
793 if (negative_hits.Contains (name))
796 // Sadly, split takes a param array, so this ends up allocating *EVERY TIME*
797 string [] elements = name.Split (dot_array);
798 int count = elements.Length;
800 for (int n = 1; n <= count; n++){
801 string top_level_type = String.Join (".", elements, 0, n);
803 // One third of the failures are caught here.
804 if (negative_hits.Contains (top_level_type))
807 t = (Type) types [top_level_type];
809 t = LookupTypeReflection (top_level_type);
811 negative_hits [top_level_type] = null;
822 // We know that System.Object does not have children, and since its the parent of
823 // all the objects, it always gets probbed for inner classes.
825 if (top_level_type == "System.Object")
828 string newt = top_level_type + "+" + String.Join ("+", elements, n, count - n);
829 //Console.WriteLine ("Looking up: " + newt + " " + name);
830 t = LookupTypeReflection (newt);
832 negative_hits [name] = null;
837 negative_hits [name] = null;
842 /// Computes the namespaces that we import from the assemblies we reference.
844 public static void ComputeNamespaces ()
846 MethodInfo assembly_get_namespaces = typeof (Assembly).GetMethod ("GetNamespaces", BindingFlags.Instance|BindingFlags.NonPublic);
849 // First add the assembly namespaces
851 if (assembly_get_namespaces != null){
852 int count = assemblies.Length;
854 for (int i = 0; i < count; i++){
855 Assembly a = assemblies [i];
856 string [] namespaces = (string []) assembly_get_namespaces.Invoke (a, null);
857 foreach (string ns in namespaces){
860 Namespace.LookupNamespace (ns, true);
864 Hashtable cache = new Hashtable ();
865 cache.Add ("", null);
866 foreach (Assembly a in assemblies) {
867 foreach (Type t in a.GetExportedTypes ()) {
868 string ns = t.Namespace;
869 if (ns == null || cache.Contains (ns))
872 Namespace.LookupNamespace (ns, true);
873 cache.Add (ns, null);
880 /// Fills static table with exported types from all referenced assemblies.
881 /// This information is required for CLS Compliance tests.
883 public static void LoadAllImportedTypes ()
885 all_imported_types = new Hashtable ();
886 foreach (Assembly a in assemblies) {
887 foreach (Type t in a.GetExportedTypes ()) {
888 all_imported_types [t.FullName] = t;
893 public static bool NamespaceClash (string name, Location loc)
895 if (Namespace.LookupNamespace (name, false) == null)
898 Report.Error (519, loc, String.Format ("`{0}' clashes with a predefined namespace", name));
903 /// Returns the C# name of a type if possible, or the full type name otherwise
905 static public string CSharpName (Type t)
907 if (t.FullName == null)
910 return Regex.Replace (t.FullName,
912 @"(Int32|UInt32|Int16|UInt16|Int64|UInt64|" +
913 @"Single|Double|Char|Decimal|Byte|SByte|Object|" +
914 @"Boolean|String|Void|Null)" +
916 new MatchEvaluator (CSharpNameMatch));
919 static String CSharpNameMatch (Match match)
921 string s = match.Groups [1].Captures [0].Value;
923 Replace ("int32", "int").
924 Replace ("uint32", "uint").
925 Replace ("int16", "short").
926 Replace ("uint16", "ushort").
927 Replace ("int64", "long").
928 Replace ("uint64", "ulong").
929 Replace ("single", "float").
930 Replace ("boolean", "bool")
931 + match.Groups [2].Captures [0].Value;
935 /// Returns the signature of the method with full namespace classification
937 static public string GetFullNameSignature (MemberInfo mi)
939 return mi.DeclaringType.FullName.Replace ('+', '.') + '.' + mi.Name;
942 static public string GetFullNameSignature (MethodBase mb)
944 string name = mb.Name;
946 name = mb.DeclaringType.Name;
948 if (mb.IsSpecialName) {
949 if (name.StartsWith ("get_") || name.StartsWith ("set_")) {
950 name = name.Remove (0, 4);
957 return mb.DeclaringType.FullName.Replace ('+', '.') + '.' + name;
960 static public string GetFullName (Type t)
962 if (t.FullName == null)
965 string name = t.FullName.Replace ('+', '.');
967 DeclSpace tc = LookupDeclSpace (t);
968 if ((tc != null) && tc.IsGeneric) {
969 TypeParameter[] tparam = tc.TypeParameters;
971 StringBuilder sb = new StringBuilder (name);
973 for (int i = 0; i < tparam.Length; i++) {
976 sb.Append (tparam [i].Name);
979 return sb.ToString ();
980 } else if (t.HasGenericArguments && !t.IsGenericInstance) {
981 Type[] tparam = t.GetGenericArguments ();
983 StringBuilder sb = new StringBuilder (name);
985 for (int i = 0; i < tparam.Length; i++) {
988 sb.Append (tparam [i].Name);
991 return sb.ToString ();
998 /// Returns the signature of the property and indexer
1000 static public string CSharpSignature (PropertyBuilder pb, bool is_indexer)
1003 return GetFullNameSignature (pb);
1006 MethodBase mb = pb.GetSetMethod (true) != null ? pb.GetSetMethod (true) : pb.GetGetMethod (true);
1007 string signature = GetFullNameSignature (mb);
1008 string arg = TypeManager.LookupParametersByBuilder (mb).ParameterDesc (0);
1009 return String.Format ("{0}.this[{1}]", signature.Substring (0, signature.LastIndexOf ('.')), arg);
1013 /// Returns the signature of the method
1015 static public string CSharpSignature (MethodBase mb)
1017 StringBuilder sig = new StringBuilder ("(");
1020 // FIXME: We should really have a single function to do
1021 // everything instead of the following 5 line pattern
1023 ParameterData iparams = LookupParametersByBuilder (mb);
1025 if (iparams == null)
1026 iparams = new ReflectionParameters (mb);
1029 if (mb.IsSpecialName && iparams.Count == 0 && !mb.IsConstructor)
1030 return GetFullNameSignature (mb);
1032 for (int i = 0; i < iparams.Count; i++) {
1036 sig.Append (iparams.ParameterDesc (i));
1041 if (mb.IsSpecialName && iparams.Count == 1 && !mb.IsConstructor) {
1042 sig.Replace ('(', '[');
1043 sig.Replace (')', ']');
1046 return GetFullNameSignature (mb) + sig.ToString ();
1050 /// Looks up a type, and aborts if it is not found. This is used
1051 /// by types required by the compiler
1053 static Type CoreLookupType (string name)
1055 Type t = LookupTypeDirect (name);
1058 Report.Error (518, "The predefined type `" + name + "' is not defined or imported");
1059 Environment.Exit (1);
1066 /// Returns the MethodInfo for a method named `name' defined
1067 /// in type `t' which takes arguments of types `args'
1069 static MethodInfo GetMethod (Type t, string name, Type [] args, bool is_private, bool report_errors)
1073 BindingFlags flags = instance_and_static | BindingFlags.Public;
1079 flags |= BindingFlags.NonPublic;
1081 list = FindMembers (t, MemberTypes.Method, flags, signature_filter, sig);
1082 if (list.Count == 0) {
1084 Report.Error (-19, "Can not find the core function `" + name + "'");
1088 MethodInfo mi = list [0] as MethodInfo;
1091 Report.Error (-19, "Can not find the core function `" + name + "'");
1098 static MethodInfo GetMethod (Type t, string name, Type [] args, bool report_errors)
1100 return GetMethod (t, name, args, false, report_errors);
1103 static MethodInfo GetMethod (Type t, string name, Type [] args)
1105 return GetMethod (t, name, args, true);
1110 /// Returns the ConstructorInfo for "args"
1112 static ConstructorInfo GetConstructor (Type t, Type [] args)
1120 list = FindMembers (t, MemberTypes.Constructor,
1121 instance_and_static | BindingFlags.Public | BindingFlags.DeclaredOnly,
1122 signature_filter, sig);
1123 if (list.Count == 0){
1124 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
1128 ConstructorInfo ci = list [0] as ConstructorInfo;
1130 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
1137 public static void InitEnumUnderlyingTypes ()
1140 int32_type = CoreLookupType ("System.Int32");
1141 int64_type = CoreLookupType ("System.Int64");
1142 uint32_type = CoreLookupType ("System.UInt32");
1143 uint64_type = CoreLookupType ("System.UInt64");
1144 byte_type = CoreLookupType ("System.Byte");
1145 sbyte_type = CoreLookupType ("System.SByte");
1146 short_type = CoreLookupType ("System.Int16");
1147 ushort_type = CoreLookupType ("System.UInt16");
1151 /// The types have to be initialized after the initial
1152 /// population of the type has happened (for example, to
1153 /// bootstrap the corlib.dll
1155 public static void InitCoreTypes ()
1157 object_type = CoreLookupType ("System.Object");
1158 value_type = CoreLookupType ("System.ValueType");
1160 InitEnumUnderlyingTypes ();
1162 char_type = CoreLookupType ("System.Char");
1163 string_type = CoreLookupType ("System.String");
1164 float_type = CoreLookupType ("System.Single");
1165 double_type = CoreLookupType ("System.Double");
1166 char_ptr_type = CoreLookupType ("System.Char*");
1167 decimal_type = CoreLookupType ("System.Decimal");
1168 bool_type = CoreLookupType ("System.Boolean");
1169 enum_type = CoreLookupType ("System.Enum");
1171 multicast_delegate_type = CoreLookupType ("System.MulticastDelegate");
1172 delegate_type = CoreLookupType ("System.Delegate");
1174 array_type = CoreLookupType ("System.Array");
1175 void_type = CoreLookupType ("System.Void");
1176 type_type = CoreLookupType ("System.Type");
1178 runtime_field_handle_type = CoreLookupType ("System.RuntimeFieldHandle");
1179 runtime_argument_handle_type = CoreLookupType ("System.RuntimeArgumentHandle");
1180 runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices.RuntimeHelpers");
1181 default_member_type = CoreLookupType ("System.Reflection.DefaultMemberAttribute");
1182 runtime_handle_type = CoreLookupType ("System.RuntimeTypeHandle");
1183 asynccallback_type = CoreLookupType ("System.AsyncCallback");
1184 iasyncresult_type = CoreLookupType ("System.IAsyncResult");
1185 ienumerator_type = CoreLookupType ("System.Collections.IEnumerator");
1186 ienumerable_type = CoreLookupType ("System.Collections.IEnumerable");
1187 idisposable_type = CoreLookupType ("System.IDisposable");
1188 icloneable_type = CoreLookupType ("System.ICloneable");
1189 iconvertible_type = CoreLookupType ("System.IConvertible");
1190 monitor_type = CoreLookupType ("System.Threading.Monitor");
1191 intptr_type = CoreLookupType ("System.IntPtr");
1193 attribute_type = CoreLookupType ("System.Attribute");
1194 attribute_usage_type = CoreLookupType ("System.AttributeUsageAttribute");
1195 dllimport_type = CoreLookupType ("System.Runtime.InteropServices.DllImportAttribute");
1196 methodimpl_attr_type = CoreLookupType ("System.Runtime.CompilerServices.MethodImplAttribute");
1197 marshal_as_attr_type = CoreLookupType ("System.Runtime.InteropServices.MarshalAsAttribute");
1198 new_constraint_attr_type = CoreLookupType ("System.Runtime.CompilerServices.NewConstraintAttribute");
1199 param_array_type = CoreLookupType ("System.ParamArrayAttribute");
1200 in_attribute_type = CoreLookupType ("System.Runtime.InteropServices.InAttribute");
1201 typed_reference_type = CoreLookupType ("System.TypedReference");
1202 arg_iterator_type = CoreLookupType ("System.ArgIterator");
1203 mbr_type = CoreLookupType ("System.MarshalByRefObject");
1206 // Sigh. Remove this before the release. Wonder what versions of Mono
1207 // people are running.
1209 guid_attr_type = LookupType ("System.Runtime.InteropServices.GuidAttribute");
1211 unverifiable_code_type= CoreLookupType ("System.Security.UnverifiableCodeAttribute");
1213 void_ptr_type = CoreLookupType ("System.Void*");
1215 indexer_name_type = CoreLookupType ("System.Runtime.CompilerServices.IndexerNameAttribute");
1217 exception_type = CoreLookupType ("System.Exception");
1218 activator_type = CoreLookupType ("System.Activator");
1219 invalid_operation_exception_type = CoreLookupType ("System.InvalidOperationException");
1220 not_supported_exception_type = CoreLookupType ("System.NotSupportedException");
1225 obsolete_attribute_type = CoreLookupType ("System.ObsoleteAttribute");
1226 conditional_attribute_type = CoreLookupType ("System.Diagnostics.ConditionalAttribute");
1227 cls_compliant_attribute_type = CoreLookupType ("System.CLSCompliantAttribute");
1228 struct_layout_attribute_type = CoreLookupType ("System.Runtime.InteropServices.StructLayoutAttribute");
1229 field_offset_attribute_type = CoreLookupType ("System.Runtime.InteropServices.FieldOffsetAttribute");
1234 generic_ienumerator_type = CoreLookupType (MemberName.MakeName ("System.Collections.Generic.IEnumerator", 1));
1235 generic_ienumerable_type = CoreLookupType (MemberName.MakeName ("System.Collections.Generic.IEnumerable", 1));
1239 // When compiling corlib, store the "real" types here.
1241 if (!RootContext.StdLib) {
1242 system_int32_type = typeof (System.Int32);
1243 system_array_type = typeof (System.Array);
1244 system_type_type = typeof (System.Type);
1245 system_assemblybuilder_type = typeof (System.Reflection.Emit.AssemblyBuilder);
1247 Type [] void_arg = { };
1248 system_int_array_get_length = GetMethod (
1249 system_array_type, "get_Length", void_arg);
1250 system_int_array_get_rank = GetMethod (
1251 system_array_type, "get_Rank", void_arg);
1252 system_object_array_clone = GetMethod (
1253 system_array_type, "Clone", void_arg);
1255 Type [] system_int_arg = { system_int32_type };
1256 system_int_array_get_length_int = GetMethod (
1257 system_array_type, "GetLength", system_int_arg);
1258 system_int_array_get_upper_bound_int = GetMethod (
1259 system_array_type, "GetUpperBound", system_int_arg);
1260 system_int_array_get_lower_bound_int = GetMethod (
1261 system_array_type, "GetLowerBound", system_int_arg);
1263 Type [] system_array_int_arg = { system_array_type, system_int32_type };
1264 system_void_array_copyto_array_int = GetMethod (
1265 system_array_type, "CopyTo", system_array_int_arg);
1267 Type [] system_3_type_arg = {
1268 system_type_type, system_type_type, system_type_type };
1269 Type [] system_4_type_arg = {
1270 system_type_type, system_type_type, system_type_type, system_type_type };
1272 MethodInfo set_corlib_type_builders = GetMethod (
1273 system_assemblybuilder_type, "SetCorlibTypeBuilders",
1274 system_4_type_arg, true, false);
1276 if (set_corlib_type_builders != null) {
1277 object[] args = new object [4];
1278 args [0] = object_type;
1279 args [1] = value_type;
1280 args [2] = enum_type;
1281 args [3] = void_type;
1283 set_corlib_type_builders.Invoke (CodeGen.Assembly.Builder, args);
1285 // Compatibility for an older version of the class libs.
1286 set_corlib_type_builders = GetMethod (
1287 system_assemblybuilder_type, "SetCorlibTypeBuilders",
1288 system_3_type_arg, true, true);
1290 if (set_corlib_type_builders == null) {
1291 Report.Error (-26, "Corlib compilation is not supported in Microsoft.NET due to bugs in it");
1295 object[] args = new object [3];
1296 args [0] = object_type;
1297 args [1] = value_type;
1298 args [2] = enum_type;
1300 set_corlib_type_builders.Invoke (CodeGen.Assembly.Builder, args);
1304 system_object_expr.Type = object_type;
1305 system_string_expr.Type = string_type;
1306 system_boolean_expr.Type = bool_type;
1307 system_decimal_expr.Type = decimal_type;
1308 system_single_expr.Type = float_type;
1309 system_double_expr.Type = double_type;
1310 system_sbyte_expr.Type = sbyte_type;
1311 system_byte_expr.Type = byte_type;
1312 system_int16_expr.Type = short_type;
1313 system_uint16_expr.Type = ushort_type;
1314 system_int32_expr.Type = int32_type;
1315 system_uint32_expr.Type = uint32_type;
1316 system_int64_expr.Type = int64_type;
1317 system_uint64_expr.Type = uint64_type;
1318 system_char_expr.Type = char_type;
1319 system_void_expr.Type = void_type;
1320 system_asynccallback_expr.Type = asynccallback_type;
1321 system_iasyncresult_expr.Type = iasyncresult_type;
1322 system_valuetype_expr.Type = value_type;
1326 // The helper methods that are used by the compiler
1328 public static void InitCodeHelpers ()
1331 // Now load the default methods that we use.
1333 Type [] string_string = { string_type, string_type };
1334 string_concat_string_string = GetMethod (
1335 string_type, "Concat", string_string);
1336 Type [] string_string_string = { string_type, string_type, string_type };
1337 string_concat_string_string_string = GetMethod (
1338 string_type, "Concat", string_string_string);
1339 Type [] string_string_string_string = { string_type, string_type, string_type, string_type };
1340 string_concat_string_string_string_string = GetMethod (
1341 string_type, "Concat", string_string_string_string);
1342 Type[] params_string = { TypeManager.LookupType ("System.String[]") };
1343 string_concat_string_dot_dot_dot = GetMethod (
1344 string_type, "Concat", params_string);
1346 Type [] object_object = { object_type, object_type };
1347 string_concat_object_object = GetMethod (
1348 string_type, "Concat", object_object);
1349 Type [] object_object_object = { object_type, object_type, object_type };
1350 string_concat_object_object_object = GetMethod (
1351 string_type, "Concat", object_object_object);
1352 Type[] params_object = { TypeManager.LookupType ("System.Object[]") };
1353 string_concat_object_dot_dot_dot = GetMethod (
1354 string_type, "Concat", params_object);
1356 Type [] string_ = { string_type };
1357 string_isinterneted_string = GetMethod (
1358 string_type, "IsInterned", string_);
1360 Type [] runtime_type_handle = { runtime_handle_type };
1361 system_type_get_type_from_handle = GetMethod (
1362 type_type, "GetTypeFromHandle", runtime_type_handle);
1364 Type [] delegate_delegate = { delegate_type, delegate_type };
1365 delegate_combine_delegate_delegate = GetMethod (
1366 delegate_type, "Combine", delegate_delegate);
1368 delegate_remove_delegate_delegate = GetMethod (
1369 delegate_type, "Remove", delegate_delegate);
1374 Type [] void_arg = { };
1375 object_getcurrent_void = GetMethod (
1376 ienumerator_type, "get_Current", void_arg);
1377 bool_movenext_void = GetMethod (
1378 ienumerator_type, "MoveNext", void_arg);
1379 void_reset_void = GetMethod (
1380 ienumerator_type, "Reset", void_arg);
1381 void_dispose_void = GetMethod (
1382 idisposable_type, "Dispose", void_arg);
1383 int_get_offset_to_string_data = GetMethod (
1384 runtime_helpers_type, "get_OffsetToStringData", void_arg);
1385 int_array_get_length = GetMethod (
1386 array_type, "get_Length", void_arg);
1387 int_array_get_rank = GetMethod (
1388 array_type, "get_Rank", void_arg);
1389 ienumerable_getenumerator_void = GetMethod (
1390 ienumerable_type, "GetEnumerator", void_arg);
1395 Type [] int_arg = { int32_type };
1396 int_array_get_length_int = GetMethod (
1397 array_type, "GetLength", int_arg);
1398 int_array_get_upper_bound_int = GetMethod (
1399 array_type, "GetUpperBound", int_arg);
1400 int_array_get_lower_bound_int = GetMethod (
1401 array_type, "GetLowerBound", int_arg);
1404 // System.Array methods
1406 object_array_clone = GetMethod (
1407 array_type, "Clone", void_arg);
1408 Type [] array_int_arg = { array_type, int32_type };
1409 void_array_copyto_array_int = GetMethod (
1410 array_type, "CopyTo", array_int_arg);
1415 Type [] object_arg = { object_type };
1416 void_monitor_enter_object = GetMethod (
1417 monitor_type, "Enter", object_arg);
1418 void_monitor_exit_object = GetMethod (
1419 monitor_type, "Exit", object_arg);
1421 Type [] array_field_handle_arg = { array_type, runtime_field_handle_type };
1423 void_initializearray_array_fieldhandle = GetMethod (
1424 runtime_helpers_type, "InitializeArray", array_field_handle_arg);
1429 int_getlength_int = GetMethod (
1430 array_type, "GetLength", int_arg);
1433 // Decimal constructors
1435 Type [] dec_arg = { int32_type, int32_type, int32_type, bool_type, byte_type };
1436 void_decimal_ctor_five_args = GetConstructor (
1437 decimal_type, dec_arg);
1442 cons_param_array_attribute = GetConstructor (
1443 param_array_type, void_arg);
1445 unverifiable_code_ctor = GetConstructor (
1446 unverifiable_code_type, void_arg);
1448 default_member_ctor = GetConstructor (default_member_type, string_);
1451 // InvalidOperationException
1453 invalid_operation_ctor = GetConstructor (
1454 invalid_operation_exception_type, void_arg);
1458 object_ctor = GetConstructor (object_type, void_arg);
1461 Type [] type_arg = { type_type };
1462 activator_create_instance = GetMethod (
1463 activator_type, "CreateInstance", type_arg);
1466 const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance;
1469 /// This is the "old", non-cache based FindMembers() function. We cannot use
1470 /// the cache here because there is no member name argument.
1472 public static MemberList FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1473 MemberFilter filter, object criteria)
1475 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
1478 // `builder_to_declspace' contains all dynamic types.
1482 Timer.StartTimer (TimerType.FindMembers);
1483 list = decl.FindMembers (mt, bf, filter, criteria);
1484 Timer.StopTimer (TimerType.FindMembers);
1489 // We have to take care of arrays specially, because GetType on
1490 // a TypeBuilder array will return a Type, not a TypeBuilder,
1491 // and we can not call FindMembers on this type.
1493 if (t.IsSubclassOf (TypeManager.array_type))
1494 return new MemberList (TypeManager.array_type.FindMembers (mt, bf, filter, criteria));
1496 if (t is GenericTypeParameterBuilder) {
1497 TypeParameter tparam = (TypeParameter) builder_to_type_param [t];
1499 Timer.StartTimer (TimerType.FindMembers);
1500 MemberList list = tparam.FindMembers (
1501 mt, bf | BindingFlags.DeclaredOnly, filter, criteria);
1502 Timer.StopTimer (TimerType.FindMembers);
1507 // Since FindMembers will not lookup both static and instance
1508 // members, we emulate this behaviour here.
1510 if ((bf & instance_and_static) == instance_and_static){
1511 MemberInfo [] i_members = t.FindMembers (
1512 mt, bf & ~BindingFlags.Static, filter, criteria);
1514 int i_len = i_members.Length;
1516 MemberInfo one = i_members [0];
1519 // If any of these are present, we are done!
1521 if ((one is Type) || (one is EventInfo) || (one is FieldInfo))
1522 return new MemberList (i_members);
1525 MemberInfo [] s_members = t.FindMembers (
1526 mt, bf & ~BindingFlags.Instance, filter, criteria);
1528 int s_len = s_members.Length;
1529 if (i_len > 0 || s_len > 0)
1530 return new MemberList (i_members, s_members);
1533 return new MemberList (i_members);
1535 return new MemberList (s_members);
1539 return new MemberList (t.FindMembers (mt, bf, filter, criteria));
1544 /// This method is only called from within MemberLookup. It tries to use the member
1545 /// cache if possible and falls back to the normal FindMembers if not. The `used_cache'
1546 /// flag tells the caller whether we used the cache or not. If we used the cache, then
1547 /// our return value will already contain all inherited members and the caller don't need
1548 /// to check base classes and interfaces anymore.
1550 private static MemberInfo [] MemberLookup_FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1551 string name, out bool used_cache)
1554 // We have to take care of arrays specially, because GetType on
1555 // a TypeBuilder array will return a Type, not a TypeBuilder,
1556 // and we can not call FindMembers on this type.
1558 if (t == TypeManager.array_type || t.IsSubclassOf (TypeManager.array_type)) {
1560 return TypeHandle.ArrayType.MemberCache.FindMembers (
1561 mt, bf, name, FilterWithClosure_delegate, null);
1565 // If this is a dynamic type, it's always in the `builder_to_declspace' hash table
1566 // and we can ask the DeclSpace for the MemberCache.
1568 if (t is TypeBuilder) {
1569 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
1570 MemberCache cache = decl.MemberCache;
1573 // If this DeclSpace has a MemberCache, use it.
1576 if (cache != null) {
1578 return cache.FindMembers (
1579 mt, bf, name, FilterWithClosure_delegate, null);
1582 // If there is no MemberCache, we need to use the "normal" FindMembers.
1583 // Note, this is a VERY uncommon route!
1586 Timer.StartTimer (TimerType.FindMembers);
1587 list = decl.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
1588 FilterWithClosure_delegate, name);
1589 Timer.StopTimer (TimerType.FindMembers);
1591 return (MemberInfo []) list;
1594 if (t is GenericTypeParameterBuilder) {
1595 TypeParameter tparam = (TypeParameter) builder_to_type_param [t];
1598 Timer.StartTimer (TimerType.FindMembers);
1599 list = tparam.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
1600 FilterWithClosure_delegate, name);
1601 Timer.StopTimer (TimerType.FindMembers);
1603 return (MemberInfo []) list;
1607 // This call will always succeed. There is exactly one TypeHandle instance per
1608 // type, TypeHandle.GetTypeHandle() will either return it or create a new one
1609 // if it didn't already exist.
1611 TypeHandle handle = TypeHandle.GetTypeHandle (t);
1614 return handle.MemberCache.FindMembers (mt, bf, name, FilterWithClosure_delegate, null);
1617 public static bool IsBuiltinType (Type t)
1619 if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
1620 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1621 t == char_type || t == short_type || t == decimal_type || t == bool_type ||
1622 t == sbyte_type || t == byte_type || t == ushort_type || t == void_type)
1628 public static bool IsBuiltinType (TypeContainer tc)
1630 return IsBuiltinType (tc.TypeBuilder);
1634 // This is like IsBuiltinType, but lacks decimal_type, we should also clean up
1635 // the pieces in the code where we use IsBuiltinType and special case decimal_type.
1637 public static bool IsCLRType (Type t)
1639 if (t == object_type || t == int32_type || t == uint32_type ||
1640 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1641 t == char_type || t == short_type || t == bool_type ||
1642 t == sbyte_type || t == byte_type || t == ushort_type)
1648 public static bool IsDelegateType (Type t)
1650 if (t.IsGenericInstance)
1651 t = t.GetGenericTypeDefinition ();
1653 if (t.IsSubclassOf (TypeManager.delegate_type))
1659 public static bool IsEnumType (Type t)
1661 if (t.IsSubclassOf (TypeManager.enum_type))
1666 public static bool IsBuiltinOrEnum (Type t)
1668 if (IsBuiltinType (t))
1678 // Only a quick hack to get things moving, while real runtime support appears
1680 public static bool IsGeneric (Type t)
1682 DeclSpace ds = (DeclSpace) builder_to_declspace [t];
1684 return ds.IsGeneric;
1687 public static bool HasGenericArguments (Type t)
1689 return GetNumberOfTypeArguments (t) > 0;
1692 public static int GetNumberOfTypeArguments (Type t)
1694 DeclSpace tc = LookupDeclSpace (t);
1696 return tc.IsGeneric ? tc.CountTypeParameters : 0;
1698 return t.HasGenericArguments ? t.GetGenericArguments ().Length : 0;
1701 public static Type[] GetTypeArguments (Type t)
1703 DeclSpace tc = LookupDeclSpace (t);
1706 throw new InvalidOperationException ();
1708 TypeParameter[] tparam = tc.TypeParameters;
1709 Type[] ret = new Type [tparam.Length];
1710 for (int i = 0; i < tparam.Length; i++) {
1711 ret [i] = tparam [i].Type;
1712 if (ret [i] == null)
1713 throw new InternalErrorException ();
1718 return t.GetGenericArguments ();
1722 // Whether a type is unmanaged. This is used by the unsafe code (25.2)
1724 public static bool IsUnmanagedType (Type t)
1726 if (IsBuiltinType (t) && t != TypeManager.string_type)
1735 if (IsValueType (t)){
1736 if (t is TypeBuilder){
1737 TypeContainer tc = LookupTypeContainer (t);
1739 if (tc.Fields != null){
1740 foreach (Field f in tc.Fields){
1741 if (f.FieldBuilder.IsStatic)
1743 if (!IsUnmanagedType (f.FieldBuilder.FieldType))
1749 FieldInfo [] fields = t.GetFields ();
1751 foreach (FieldInfo f in fields){
1754 if (!IsUnmanagedType (f.FieldType))
1764 public static bool IsValueType (Type t)
1766 return t.IsGenericParameter || t.IsValueType;
1769 public static bool IsInterfaceType (Type t)
1771 TypeContainer tc = (TypeContainer) builder_to_declspace [t];
1775 return tc.Kind == Kind.Interface;
1778 public static bool IsEqual (Type a, Type b)
1783 if ((a is TypeBuilder) && a.IsGenericTypeDefinition && b.IsGenericInstance) {
1785 // `a' is a generic type definition's TypeBuilder and `b' is a
1786 // generic instance of the same type.
1792 // void Test (Stack<T> stack) { }
1795 // The first argument of `Test' will be the generic instance
1796 // "Stack<!0>" - which is the same type than the "Stack" TypeBuilder.
1799 // We hit this via Closure.Filter() for gen-82.cs.
1801 if (a != b.GetGenericTypeDefinition ())
1804 Type[] aparams = a.GetGenericArguments ();
1805 Type[] bparams = b.GetGenericArguments ();
1807 if (aparams.Length != bparams.Length)
1810 for (int i = 0; i < aparams.Length; i++)
1811 if (!IsEqual (aparams [i], bparams [i]))
1817 if (a.IsGenericParameter && b.IsGenericParameter) {
1818 if ((a.DeclaringMethod == null) || (b.DeclaringMethod == null))
1820 return a.GenericParameterPosition == b.GenericParameterPosition;
1823 if (a.IsArray && b.IsArray) {
1824 if (a.GetArrayRank () != b.GetArrayRank ())
1826 return IsEqual (a.GetElementType (), b.GetElementType ());
1829 if (a.IsGenericInstance && b.IsGenericInstance) {
1830 Type at = a.GetGenericTypeDefinition ();
1831 Type bt = b.GetGenericTypeDefinition ();
1833 if (a.GetGenericTypeDefinition () != b.GetGenericTypeDefinition ())
1836 Type[] aargs = a.GetGenericArguments ();
1837 Type[] bargs = b.GetGenericArguments ();
1839 if (aargs.Length != bargs.Length)
1842 for (int i = 0; i < aargs.Length; i++) {
1843 if (!IsEqual (aargs [i], bargs [i]))
1853 public static bool MayBecomeEqualGenericTypes (Type a, Type b)
1855 if (a.IsGenericParameter) {
1857 // If a is an array of a's type, they may never
1861 b = b.GetElementType ();
1867 // If b is a generic parameter or an actual type,
1868 // they may become equal:
1870 // class X<T,U> : I<T>, I<U>
1871 // class X<T> : I<T>, I<float>
1873 if (b.IsGenericParameter || !b.IsGenericInstance)
1877 // We're now comparing a type parameter with a
1878 // generic instance. They may become equal unless
1879 // the type parameter appears anywhere in the
1880 // generic instance:
1882 // class X<T,U> : I<T>, I<X<U>>
1883 // -> error because you could instanciate it as
1886 // class X<T> : I<T>, I<X<T>> -> ok
1889 Type[] bargs = GetTypeArguments (b);
1890 for (int i = 0; i < bargs.Length; i++) {
1891 if (a.Equals (bargs [i]))
1898 if (b.IsGenericParameter)
1899 return MayBecomeEqualGenericTypes (b, a);
1902 // At this point, neither a nor b are a type parameter.
1904 // If one of them is a generic instance, let
1905 // MayBecomeEqualGenericInstances() compare them (if the
1906 // other one is not a generic instance, they can never
1910 if (a.IsGenericInstance || b.IsGenericInstance)
1911 return MayBecomeEqualGenericInstances (a, b);
1914 // If both of them are arrays.
1917 if (a.IsArray && b.IsArray) {
1918 if (a.GetArrayRank () != b.GetArrayRank ())
1921 a = a.GetElementType ();
1922 b = b.GetElementType ();
1924 return MayBecomeEqualGenericTypes (a, b);
1928 // Ok, two ordinary types.
1931 return a.Equals (b);
1935 // Checks whether two generic instances may become equal for some
1936 // particular instantiation (26.3.1).
1938 public static bool MayBecomeEqualGenericInstances (Type a, Type b)
1940 if (!a.IsGenericInstance || !b.IsGenericInstance)
1942 if (a.GetGenericTypeDefinition () != b.GetGenericTypeDefinition ())
1945 Type[] aargs = GetTypeArguments (a);
1946 Type[] bargs = GetTypeArguments (b);
1948 if (aargs.Length != bargs.Length)
1951 for (int i = 0; i < aargs.Length; i++) {
1952 if (MayBecomeEqualGenericTypes (aargs [i], bargs [i]))
1959 public static bool IsEqualGenericInstance (Type type, Type parent)
1961 int tcount = GetNumberOfTypeArguments (type);
1962 int pcount = GetNumberOfTypeArguments (parent);
1964 if (type.IsGenericInstance)
1965 type = type.GetGenericTypeDefinition ();
1966 if (parent.IsGenericInstance)
1967 parent = parent.GetGenericTypeDefinition ();
1969 if (tcount != pcount)
1972 return type.Equals (parent);
1975 public static bool IsSubclassOf (Type type, Type parent)
1977 TypeParameter tparam = LookupTypeParameter (type);
1978 TypeParameter pparam = LookupTypeParameter (parent);
1980 if ((tparam != null) && (pparam != null)) {
1981 if (tparam == pparam)
1984 return tparam.IsSubclassOf (parent);
1988 if (type.Equals (parent))
1991 type = type.BaseType;
1992 } while (type != null);
1997 public static bool IsPrivateAccessible (Type type, Type parent)
1999 if (type.Equals (parent))
2002 if ((type is TypeBuilder) && type.IsGenericTypeDefinition && parent.IsGenericInstance) {
2004 // `a' is a generic type definition's TypeBuilder and `b' is a
2005 // generic instance of the same type.
2011 // void Test (Stack<T> stack) { }
2014 // The first argument of `Test' will be the generic instance
2015 // "Stack<!0>" - which is the same type than the "Stack" TypeBuilder.
2018 // We hit this via Closure.Filter() for gen-82.cs.
2020 if (type != parent.GetGenericTypeDefinition ())
2026 if (type.IsGenericInstance && parent.IsGenericInstance) {
2027 Type tdef = type.GetGenericTypeDefinition ();
2028 Type pdef = parent.GetGenericTypeDefinition ();
2030 if (type.GetGenericTypeDefinition () != parent.GetGenericTypeDefinition ())
2039 public static bool IsFamilyAccessible (Type type, Type parent)
2041 TypeParameter tparam = LookupTypeParameter (type);
2042 TypeParameter pparam = LookupTypeParameter (parent);
2044 if ((tparam != null) && (pparam != null)) {
2045 if (tparam == pparam)
2048 return tparam.IsSubclassOf (parent);
2052 if (IsEqualGenericInstance (type, parent))
2055 type = type.BaseType;
2056 } while (type != null);
2062 // Checks whether `type' is a subclass or nested child of `parent'.
2064 public static bool IsNestedFamilyAccessible (Type type, Type parent)
2067 if (IsFamilyAccessible (type, parent))
2070 // Handle nested types.
2071 type = type.DeclaringType;
2072 } while (type != null);
2078 // Checks whether `type' is a nested child of `parent'.
2080 public static bool IsNestedChildOf (Type type, Type parent)
2082 if (IsEqual (type, parent))
2085 type = type.DeclaringType;
2086 while (type != null) {
2087 if (IsEqual (type, parent))
2090 type = type.DeclaringType;
2097 // Do the right thing when returning the element type of an
2098 // array type based on whether we are compiling corlib or not
2100 public static Type GetElementType (Type t)
2102 if (RootContext.StdLib)
2103 return t.GetElementType ();
2105 return TypeToCoreType (t.GetElementType ());
2109 /// Returns the User Defined Types
2111 public static ArrayList UserTypes {
2117 public static Hashtable TypeContainers {
2119 return typecontainers;
2123 static Hashtable builder_to_constant;
2125 public static void RegisterConstant (FieldBuilder fb, Const c)
2127 if (builder_to_constant == null)
2128 builder_to_constant = new PtrHashtable ();
2130 if (builder_to_constant.Contains (fb))
2133 builder_to_constant.Add (fb, c);
2136 public static Const LookupConstant (FieldBuilder fb)
2138 if (builder_to_constant == null)
2141 return (Const) builder_to_constant [fb];
2145 /// Gigantic work around for missing features in System.Reflection.Emit follows.
2149 /// Since System.Reflection.Emit can not return MethodBase.GetParameters
2150 /// for anything which is dynamic, and we need this in a number of places,
2151 /// we register this information here, and use it afterwards.
2153 static public void RegisterMethod (MethodBase mb, InternalParameters ip, Type [] args)
2158 method_arguments.Add (mb, args);
2159 method_internal_params.Add (mb, ip);
2162 static public InternalParameters LookupParametersByBuilder (MethodBase mb)
2164 if (! (mb is ConstructorBuilder || mb is MethodBuilder))
2167 if (method_internal_params.Contains (mb))
2168 return (InternalParameters) method_internal_params [mb];
2170 throw new Exception ("Argument for Method not registered" + mb);
2174 /// Returns the argument types for a method based on its methodbase
2176 /// For dynamic methods, we use the compiler provided types, for
2177 /// methods from existing assemblies we load them from GetParameters,
2178 /// and insert them into the cache
2180 static public Type [] GetArgumentTypes (MethodBase mb)
2182 object t = method_arguments [mb];
2186 ParameterInfo [] pi = mb.GetParameters ();
2193 types = new Type [c];
2194 for (int i = 0; i < c; i++)
2195 types [i] = pi [i].ParameterType;
2197 method_arguments.Add (mb, types);
2202 /// Returns the argument types for an indexer based on its PropertyInfo
2204 /// For dynamic indexers, we use the compiler provided types, for
2205 /// indexers from existing assemblies we load them from GetParameters,
2206 /// and insert them into the cache
2208 static public Type [] GetArgumentTypes (PropertyInfo indexer)
2210 if (indexer_arguments.Contains (indexer))
2211 return (Type []) indexer_arguments [indexer];
2212 else if (indexer is PropertyBuilder)
2213 // If we're a PropertyBuilder and not in the
2214 // `indexer_arguments' hash, then we're a property and
2218 ParameterInfo [] pi = indexer.GetIndexParameters ();
2219 // Property, not an indexer.
2223 Type [] types = new Type [c];
2225 for (int i = 0; i < c; i++)
2226 types [i] = pi [i].ParameterType;
2228 indexer_arguments.Add (indexer, types);
2234 // This is a workaround the fact that GetValue is not
2235 // supported for dynamic types
2237 static Hashtable fields = new Hashtable ();
2238 static public bool RegisterFieldValue (FieldBuilder fb, object value)
2240 if (fields.Contains (fb))
2243 fields.Add (fb, value);
2248 static public object GetValue (FieldBuilder fb)
2253 static Hashtable fieldbuilders_to_fields = new Hashtable ();
2254 static public bool RegisterFieldBase (FieldBuilder fb, FieldBase f)
2256 if (fieldbuilders_to_fields.Contains (fb))
2259 fieldbuilders_to_fields.Add (fb, f);
2264 // The return value can be null; This will be the case for
2265 // auxiliary FieldBuilders created by the compiler that have no
2266 // real field being declared on the source code
2268 static public FieldBase GetField (FieldInfo fb)
2270 return (FieldBase) fieldbuilders_to_fields [fb];
2273 static Hashtable events;
2275 static public void RegisterEvent (MyEventBuilder eb, MethodBase add, MethodBase remove)
2278 events = new Hashtable ();
2280 if (!events.Contains (eb)) {
2281 events.Add (eb, new Pair (add, remove));
2285 static public MethodInfo GetAddMethod (EventInfo ei)
2287 if (ei is MyEventBuilder) {
2288 Pair pair = (Pair) events [ei];
2290 return (MethodInfo) pair.First;
2292 return ei.GetAddMethod (true);
2295 static public MethodInfo GetRemoveMethod (EventInfo ei)
2297 if (ei is MyEventBuilder) {
2298 Pair pair = (Pair) events [ei];
2300 return (MethodInfo) pair.Second;
2302 return ei.GetRemoveMethod (true);
2305 static Hashtable priv_fields_events;
2307 static public bool RegisterPrivateFieldOfEvent (EventInfo einfo, FieldBuilder builder)
2309 if (priv_fields_events == null)
2310 priv_fields_events = new Hashtable ();
2312 if (priv_fields_events.Contains (einfo))
2315 priv_fields_events.Add (einfo, builder);
2320 static public MemberInfo GetPrivateFieldOfEvent (EventInfo ei)
2322 if (priv_fields_events == null)
2325 return (MemberInfo) priv_fields_events [ei];
2328 static Hashtable properties;
2330 static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set)
2332 if (properties == null)
2333 properties = new Hashtable ();
2335 if (properties.Contains (pb))
2338 properties.Add (pb, new Pair (get, set));
2343 static public bool RegisterIndexer (PropertyBuilder pb, MethodBase get,
2344 MethodBase set, Type[] args)
2346 if (!RegisterProperty (pb, get,set))
2349 indexer_arguments.Add (pb, args);
2354 public static bool CheckStructCycles (TypeContainer tc, Hashtable seen)
2356 Hashtable hash = new Hashtable ();
2357 return CheckStructCycles (tc, seen, hash);
2360 public static bool CheckStructCycles (TypeContainer tc, Hashtable seen,
2363 if ((tc.Kind != Kind.Struct) || IsBuiltinType (tc))
2367 // `seen' contains all types we've already visited.
2369 if (seen.Contains (tc))
2371 seen.Add (tc, null);
2373 if (tc.Fields == null)
2376 foreach (Field field in tc.Fields) {
2377 if (field.FieldBuilder.IsStatic)
2380 Type ftype = field.FieldBuilder.FieldType;
2381 TypeContainer ftc = LookupTypeContainer (ftype);
2385 if (hash.Contains (ftc)) {
2386 Report.Error (523, tc.Location,
2387 "Struct member `{0}.{1}' of type `{2}' " +
2388 "causes a cycle in the struct layout",
2389 tc.Name, field.Name, ftc.Name);
2394 // `hash' contains all types in the current path.
2396 hash.Add (tc, null);
2398 bool ok = CheckStructCycles (ftc, seen, hash);
2405 if (!seen.Contains (ftc))
2406 seen.Add (ftc, null);
2413 /// Given an array of interface types, expand and eliminate repeated ocurrences
2414 /// of an interface.
2418 /// This expands in context like: IA; IB : IA; IC : IA, IB; the interface "IC" to
2421 public static Type[] ExpandInterfaces (EmitContext ec, TypeExpr [] base_interfaces)
2423 ArrayList new_ifaces = new ArrayList ();
2425 foreach (TypeExpr iface in base_interfaces){
2426 Type itype = iface.ResolveType (ec);
2430 if (!new_ifaces.Contains (itype))
2431 new_ifaces.Add (itype);
2433 Type [] implementing = itype.GetInterfaces ();
2435 foreach (Type imp in implementing){
2436 if (!new_ifaces.Contains (imp))
2437 new_ifaces.Add (imp);
2440 Type [] ret = new Type [new_ifaces.Count];
2441 new_ifaces.CopyTo (ret, 0);
2445 static PtrHashtable iface_cache = new PtrHashtable ();
2448 /// This function returns the interfaces in the type `t'. Works with
2449 /// both types and TypeBuilders.
2451 public static Type [] GetInterfaces (Type t)
2454 Type [] cached = iface_cache [t] as Type [];
2459 // The reason for catching the Array case is that Reflection.Emit
2460 // will not return a TypeBuilder for Array types of TypeBuilder types,
2461 // but will still throw an exception if we try to call GetInterfaces
2464 // Since the array interfaces are always constant, we return those for
2469 t = TypeManager.array_type;
2471 if (t is TypeBuilder){
2472 Type[] parent_ifaces;
2474 if (t.BaseType == null)
2475 parent_ifaces = NoTypes;
2477 parent_ifaces = GetInterfaces (t.BaseType);
2478 Type[] type_ifaces = (Type []) builder_to_ifaces [t];
2479 if (type_ifaces == null)
2480 type_ifaces = NoTypes;
2482 int parent_count = parent_ifaces.Length;
2483 Type[] result = new Type [parent_count + type_ifaces.Length];
2484 parent_ifaces.CopyTo (result, 0);
2485 type_ifaces.CopyTo (result, parent_count);
2487 iface_cache [t] = result;
2489 } else if (t is GenericTypeParameterBuilder){
2490 Type[] type_ifaces = (Type []) builder_to_ifaces [t];
2491 if (type_ifaces == null)
2492 type_ifaces = NoTypes;
2494 iface_cache [t] = type_ifaces;
2497 Type[] ifaces = t.GetInterfaces ();
2498 iface_cache [t] = ifaces;
2504 // gets the interfaces that are declared explicitly on t
2506 public static Type [] GetExplicitInterfaces (TypeBuilder t)
2508 return (Type []) builder_to_ifaces [t];
2512 /// The following is used to check if a given type implements an interface.
2513 /// The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
2515 public static bool ImplementsInterface (Type t, Type iface)
2520 // FIXME OPTIMIZATION:
2521 // as soon as we hit a non-TypeBuiler in the interface
2522 // chain, we could return, as the `Type.GetInterfaces'
2523 // will return all the interfaces implement by the type
2527 interfaces = GetInterfaces (t);
2529 if (interfaces != null){
2530 foreach (Type i in interfaces){
2537 } while (t != null);
2542 static NumberFormatInfo nf_provider = CultureInfo.CurrentCulture.NumberFormat;
2544 // This is a custom version of Convert.ChangeType() which works
2545 // with the TypeBuilder defined types when compiling corlib.
2546 public static object ChangeType (object value, Type conversionType, out bool error)
2548 IConvertible convert_value = value as IConvertible;
2550 if (convert_value == null){
2556 // We must use Type.Equals() here since `conversionType' is
2557 // the TypeBuilder created version of a system type and not
2558 // the system type itself. You cannot use Type.GetTypeCode()
2559 // on such a type - it'd always return TypeCode.Object.
2563 if (conversionType.Equals (typeof (Boolean)))
2564 return (object)(convert_value.ToBoolean (nf_provider));
2565 else if (conversionType.Equals (typeof (Byte)))
2566 return (object)(convert_value.ToByte (nf_provider));
2567 else if (conversionType.Equals (typeof (Char)))
2568 return (object)(convert_value.ToChar (nf_provider));
2569 else if (conversionType.Equals (typeof (DateTime)))
2570 return (object)(convert_value.ToDateTime (nf_provider));
2571 else if (conversionType.Equals (typeof (Decimal)))
2572 return (object)(convert_value.ToDecimal (nf_provider));
2573 else if (conversionType.Equals (typeof (Double)))
2574 return (object)(convert_value.ToDouble (nf_provider));
2575 else if (conversionType.Equals (typeof (Int16)))
2576 return (object)(convert_value.ToInt16 (nf_provider));
2577 else if (conversionType.Equals (typeof (Int32)))
2578 return (object)(convert_value.ToInt32 (nf_provider));
2579 else if (conversionType.Equals (typeof (Int64)))
2580 return (object)(convert_value.ToInt64 (nf_provider));
2581 else if (conversionType.Equals (typeof (SByte)))
2582 return (object)(convert_value.ToSByte (nf_provider));
2583 else if (conversionType.Equals (typeof (Single)))
2584 return (object)(convert_value.ToSingle (nf_provider));
2585 else if (conversionType.Equals (typeof (String)))
2586 return (object)(convert_value.ToString (nf_provider));
2587 else if (conversionType.Equals (typeof (UInt16)))
2588 return (object)(convert_value.ToUInt16 (nf_provider));
2589 else if (conversionType.Equals (typeof (UInt32)))
2590 return (object)(convert_value.ToUInt32 (nf_provider));
2591 else if (conversionType.Equals (typeof (UInt64)))
2592 return (object)(convert_value.ToUInt64 (nf_provider));
2593 else if (conversionType.Equals (typeof (Object)))
2594 return (object)(value);
2604 // This is needed, because enumerations from assemblies
2605 // do not report their underlyingtype, but they report
2608 public static Type EnumToUnderlying (Type t)
2610 if (t == TypeManager.enum_type)
2613 t = t.UnderlyingSystemType;
2614 if (!TypeManager.IsEnumType (t))
2617 if (t is TypeBuilder) {
2618 // slow path needed to compile corlib
2619 if (t == TypeManager.bool_type ||
2620 t == TypeManager.byte_type ||
2621 t == TypeManager.sbyte_type ||
2622 t == TypeManager.char_type ||
2623 t == TypeManager.short_type ||
2624 t == TypeManager.ushort_type ||
2625 t == TypeManager.int32_type ||
2626 t == TypeManager.uint32_type ||
2627 t == TypeManager.int64_type ||
2628 t == TypeManager.uint64_type)
2630 throw new Exception ("Unhandled typecode in enum " + " from " + t.AssemblyQualifiedName);
2632 TypeCode tc = Type.GetTypeCode (t);
2635 case TypeCode.Boolean:
2636 return TypeManager.bool_type;
2638 return TypeManager.byte_type;
2639 case TypeCode.SByte:
2640 return TypeManager.sbyte_type;
2642 return TypeManager.char_type;
2643 case TypeCode.Int16:
2644 return TypeManager.short_type;
2645 case TypeCode.UInt16:
2646 return TypeManager.ushort_type;
2647 case TypeCode.Int32:
2648 return TypeManager.int32_type;
2649 case TypeCode.UInt32:
2650 return TypeManager.uint32_type;
2651 case TypeCode.Int64:
2652 return TypeManager.int64_type;
2653 case TypeCode.UInt64:
2654 return TypeManager.uint64_type;
2656 throw new Exception ("Unhandled typecode in enum " + tc + " from " + t.AssemblyQualifiedName);
2660 // When compiling corlib and called with one of the core types, return
2661 // the corresponding typebuilder for that type.
2663 public static Type TypeToCoreType (Type t)
2665 if (RootContext.StdLib || (t is TypeBuilder))
2668 TypeCode tc = Type.GetTypeCode (t);
2671 case TypeCode.Boolean:
2672 return TypeManager.bool_type;
2674 return TypeManager.byte_type;
2675 case TypeCode.SByte:
2676 return TypeManager.sbyte_type;
2678 return TypeManager.char_type;
2679 case TypeCode.Int16:
2680 return TypeManager.short_type;
2681 case TypeCode.UInt16:
2682 return TypeManager.ushort_type;
2683 case TypeCode.Int32:
2684 return TypeManager.int32_type;
2685 case TypeCode.UInt32:
2686 return TypeManager.uint32_type;
2687 case TypeCode.Int64:
2688 return TypeManager.int64_type;
2689 case TypeCode.UInt64:
2690 return TypeManager.uint64_type;
2691 case TypeCode.Single:
2692 return TypeManager.float_type;
2693 case TypeCode.Double:
2694 return TypeManager.double_type;
2695 case TypeCode.String:
2696 return TypeManager.string_type;
2698 if (t == typeof (void))
2699 return TypeManager.void_type;
2700 if (t == typeof (object))
2701 return TypeManager.object_type;
2702 if (t == typeof (System.Type))
2703 return TypeManager.type_type;
2704 if (t == typeof (System.IntPtr))
2705 return TypeManager.intptr_type;
2711 /// Utility function that can be used to probe whether a type
2712 /// is managed or not.
2714 public static bool VerifyUnManaged (Type t, Location loc)
2716 if (t.IsValueType || t.IsPointer){
2718 // FIXME: this is more complex, we actually need to
2719 // make sure that the type does not contain any
2725 if (!RootContext.StdLib && (t == TypeManager.decimal_type))
2726 // We need this explicit check here to make it work when
2727 // compiling corlib.
2732 "Cannot take the address or size of a variable of a managed type ('" +
2733 CSharpName (t) + "')");
2738 /// Returns the name of the indexer in a given type.
2741 /// The default is not always `Item'. The user can change this behaviour by
2742 /// using the IndexerNameAttribute in the container.
2744 /// For example, the String class indexer is named `Chars' not `Item'
2746 public static string IndexerPropertyName (Type t)
2748 if (t.IsGenericInstance)
2749 t = t.GetGenericTypeDefinition ();
2751 if (t is TypeBuilder) {
2752 TypeContainer tc = t.IsInterface ? LookupInterface (t) : LookupTypeContainer (t);
2753 return tc == null ? TypeContainer.DefaultIndexerName : tc.IndexerName;
2756 System.Attribute attr = System.Attribute.GetCustomAttribute (
2757 t, TypeManager.default_member_type);
2759 DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
2760 return dma.MemberName;
2763 return TypeContainer.DefaultIndexerName;
2766 static MethodInfo declare_local_method = null;
2768 public static LocalBuilder DeclareLocalPinned (ILGenerator ig, Type t)
2770 if (declare_local_method == null){
2771 declare_local_method = typeof (ILGenerator).GetMethod (
2773 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
2775 new Type [] { typeof (Type), typeof (bool)},
2777 if (declare_local_method == null){
2778 Report.Warning (-24, new Location (-1),
2779 "This version of the runtime does not support making pinned local variables. " +
2780 "This code may cause errors on a runtime with a moving GC");
2781 return ig.DeclareLocal (t);
2784 return (LocalBuilder) declare_local_method.Invoke (ig, new object [] { t, true });
2788 // Returns whether the array of memberinfos contains the given method
2790 public static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method)
2792 Type [] new_args = TypeManager.GetArgumentTypes (new_method);
2794 foreach (MethodBase method in array) {
2795 if (method.Name != new_method.Name)
2798 if (method is MethodInfo && new_method is MethodInfo)
2799 if (((MethodInfo) method).ReturnType != ((MethodInfo) new_method).ReturnType)
2803 Type [] old_args = TypeManager.GetArgumentTypes (method);
2804 int old_count = old_args.Length;
2807 if (new_args.Length != old_count)
2810 for (i = 0; i < old_count; i++){
2811 if (old_args [i] != new_args [i])
2824 // We copy methods from `new_members' into `target_list' if the signature
2825 // for the method from in the new list does not exist in the target_list
2827 // The name is assumed to be the same.
2829 public static ArrayList CopyNewMethods (ArrayList target_list, IList new_members)
2831 if (target_list == null){
2832 target_list = new ArrayList ();
2834 foreach (MemberInfo mi in new_members){
2835 if (mi is MethodBase)
2836 target_list.Add (mi);
2841 MemberInfo [] target_array = new MemberInfo [target_list.Count];
2842 target_list.CopyTo (target_array, 0);
2844 foreach (MemberInfo mi in new_members){
2845 MethodBase new_method = (MethodBase) mi;
2847 if (!ArrayContainsMethod (target_array, new_method))
2848 target_list.Add (new_method);
2853 static public bool IsGenericMethod (MethodBase mb)
2855 if (mb.DeclaringType is TypeBuilder) {
2856 IMethodData method = (IMethodData) builder_to_method [mb];
2860 return method.GenericMethod != null;
2863 return mb.IsGenericMethodDefinition;
2866 #region MemberLookup implementation
2869 // Whether we allow private members in the result (since FindMembers
2870 // uses NonPublic for both protected and private), we need to distinguish.
2873 static internal bool FilterNone (MemberInfo m, object filter_criteria)
2878 internal class Closure {
2879 internal bool private_ok;
2881 // Who is invoking us and which type is being queried currently.
2882 internal Type invocation_type;
2883 internal Type qualifier_type;
2885 // The assembly that defines the type is that is calling us
2886 internal Assembly invocation_assembly;
2887 internal IList almost_match;
2889 private bool CheckValidFamilyAccess (bool is_static, MemberInfo m)
2891 if (invocation_type == null)
2897 // A nested class has access to all the protected members visible
2899 if (qualifier_type != null
2900 && TypeManager.IsNestedChildOf (invocation_type, qualifier_type))
2903 if (invocation_type == m.DeclaringType
2904 || invocation_type.IsSubclassOf (m.DeclaringType)) {
2905 // Although a derived class can access protected members of
2906 // its base class it cannot do so through an instance of the
2907 // base class (CS1540).
2908 // => Ancestry should be: declaring_type ->* invocation_type
2909 // ->* qualified_type
2910 if (qualifier_type == null
2911 || qualifier_type == invocation_type
2912 || qualifier_type.IsSubclassOf (invocation_type))
2916 if (almost_match != null)
2917 almost_match.Add (m);
2921 bool Filter (MethodBase mb, object filter_criteria)
2923 MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
2925 if (ma == MethodAttributes.Private)
2926 return private_ok ||
2927 IsPrivateAccessible (invocation_type, mb.DeclaringType) ||
2928 IsNestedChildOf (invocation_type, mb.DeclaringType);
2931 // FamAndAssem requires that we not only derivate, but we are on the
2934 if (ma == MethodAttributes.FamANDAssem){
2935 if (invocation_assembly != mb.DeclaringType.Assembly)
2939 // Assembly and FamORAssem succeed if we're in the same assembly.
2940 if ((ma == MethodAttributes.Assembly) || (ma == MethodAttributes.FamORAssem)){
2941 if (invocation_assembly == mb.DeclaringType.Assembly)
2945 // We already know that we aren't in the same assembly.
2946 if (ma == MethodAttributes.Assembly)
2949 // Family and FamANDAssem require that we derive.
2950 if ((ma == MethodAttributes.Family) || (ma == MethodAttributes.FamANDAssem)){
2951 if (invocation_type == null)
2954 if (!IsNestedFamilyAccessible (invocation_type, mb.DeclaringType))
2957 // Although a derived class can access protected members of its base class
2958 // it cannot do so through an instance of the base class (CS1540).
2959 if (!mb.IsStatic && (qualifier_type != null) &&
2960 !IsEqualGenericInstance (invocation_type, qualifier_type) &&
2961 TypeManager.IsFamilyAccessible (invocation_type, qualifier_type) &&
2962 !TypeManager.IsNestedChildOf (invocation_type, qualifier_type))
2972 bool Filter (FieldInfo fi, object filter_criteria)
2974 FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask;
2976 if (fa == FieldAttributes.Private)
2977 return private_ok ||
2978 IsPrivateAccessible (invocation_type, fi.DeclaringType) ||
2979 IsNestedChildOf (invocation_type, fi.DeclaringType);
2982 // FamAndAssem requires that we not only derivate, but we are on the
2985 if (fa == FieldAttributes.FamANDAssem){
2986 if (invocation_assembly != fi.DeclaringType.Assembly)
2990 // Assembly and FamORAssem succeed if we're in the same assembly.
2991 if ((fa == FieldAttributes.Assembly) || (fa == FieldAttributes.FamORAssem)){
2992 if (invocation_assembly == fi.DeclaringType.Assembly)
2996 // We already know that we aren't in the same assembly.
2997 if (fa == FieldAttributes.Assembly)
3000 // Family and FamANDAssem require that we derive.
3001 if ((fa == FieldAttributes.Family) || (fa == FieldAttributes.FamANDAssem)){
3002 if (invocation_type == null)
3005 if (!IsNestedFamilyAccessible (invocation_type, fi.DeclaringType))
3008 // Although a derived class can access protected members of its base class
3009 // it cannot do so through an instance of the base class (CS1540).
3010 if (!fi.IsStatic && (qualifier_type != null) &&
3011 !IsEqualGenericInstance (invocation_type, qualifier_type) &&
3012 TypeManager.IsFamilyAccessible (invocation_type, qualifier_type) &&
3013 !TypeManager.IsNestedChildOf (invocation_type, qualifier_type))
3024 // This filter filters by name + whether it is ok to include private
3025 // members in the search
3027 internal bool Filter (MemberInfo m, object filter_criteria)
3030 // Hack: we know that the filter criteria will always be in the
3031 // `closure' // fields.
3034 if ((filter_criteria != null) && (m.Name != (string) filter_criteria))
3037 if (((qualifier_type == null) || (qualifier_type == invocation_type)) &&
3038 (invocation_type != null) &&
3039 IsPrivateAccessible (m.DeclaringType, invocation_type))
3043 // Ugly: we need to find out the type of `m', and depending
3044 // on this, tell whether we accept or not
3046 if (m is MethodBase)
3047 return Filter ((MethodBase) m, filter_criteria);
3050 return Filter ((FieldInfo) m, filter_criteria);
3053 // EventInfos and PropertyInfos, return true because they lack
3054 // permission information, so we need to check later on the methods.
3060 static Closure closure = new Closure ();
3061 static MemberFilter FilterWithClosure_delegate = new MemberFilter (closure.Filter);
3064 // Looks up a member called `name' in the `queried_type'. This lookup
3065 // is done by code that is contained in the definition for `invocation_type'
3066 // through a qualifier of type `qualifier_type' (or null if there is no qualifier).
3068 // `invocation_type' is used to check whether we're allowed to access the requested
3069 // member wrt its protection level.
3071 // When called from MemberAccess, `qualifier_type' is the type which is used to access
3072 // the requested member (`class B { A a = new A (); a.foo = 5; }'; here invocation_type
3073 // is B and qualifier_type is A). This is used to do the CS1540 check.
3075 // When resolving a SimpleName, `qualifier_type' is null.
3077 // The `qualifier_type' is used for the CS1540 check; it's normally either null or
3078 // the same than `queried_type' - except when we're being called from BaseAccess;
3079 // in this case, `invocation_type' is the current type and `queried_type' the base
3080 // type, so this'd normally trigger a CS1540.
3082 // The binding flags are `bf' and the kind of members being looked up are `mt'
3084 // The return value always includes private members which code in `invocation_type'
3085 // is allowed to access (using the specified `qualifier_type' if given); only use
3086 // BindingFlags.NonPublic to bypass the permission check.
3088 // The 'almost_match' argument is used for reporting error CS1540.
3090 // Returns an array of a single element for everything but Methods/Constructors
3091 // that might return multiple matches.
3093 public static MemberInfo [] MemberLookup (Type invocation_type, Type qualifier_type,
3094 Type queried_type, MemberTypes mt,
3095 BindingFlags original_bf, string name, IList almost_match)
3097 Timer.StartTimer (TimerType.MemberLookup);
3099 MemberInfo[] retval = RealMemberLookup (invocation_type, qualifier_type,
3100 queried_type, mt, original_bf, name, almost_match);
3102 Timer.StopTimer (TimerType.MemberLookup);
3107 static MemberInfo [] RealMemberLookup (Type invocation_type, Type qualifier_type,
3108 Type queried_type, MemberTypes mt,
3109 BindingFlags original_bf, string name, IList almost_match)
3111 BindingFlags bf = original_bf;
3113 ArrayList method_list = null;
3114 Type current_type = queried_type;
3115 bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0;
3116 bool skip_iface_check = true, used_cache = false;
3117 bool always_ok_flag = false;
3119 closure.invocation_type = invocation_type;
3120 closure.invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
3121 closure.qualifier_type = qualifier_type;
3122 closure.almost_match = almost_match;
3125 // If we are a nested class, we always have access to our container
3128 if (invocation_type != null){
3129 string invocation_name = invocation_type.FullName;
3130 if ((invocation_name != null) && (invocation_name.IndexOf ('+') != -1)){
3131 string container = queried_type.FullName + "+";
3132 int container_length = container.Length;
3134 if (invocation_name.Length > container_length){
3135 string shared = invocation_name.Substring (0, container_length);
3137 if (shared == container)
3138 always_ok_flag = true;
3143 // This is from the first time we find a method
3144 // in most cases, we do not actually find a method in the base class
3145 // so we can just ignore it, and save the arraylist allocation
3146 MemberInfo [] first_members_list = null;
3147 bool use_first_members_list = false;
3153 // `NonPublic' is lame, because it includes both protected and
3154 // private methods, so we need to control this behavior by
3155 // explicitly tracking if a private method is ok or not.
3157 // The possible cases are:
3158 // public, private and protected (internal does not come into the
3161 if ((invocation_type != null) &&
3162 ((invocation_type == current_type) ||
3163 IsNestedChildOf (invocation_type, current_type)) ||
3165 bf = original_bf | BindingFlags.NonPublic;
3169 closure.private_ok = (original_bf & BindingFlags.NonPublic) != 0;
3171 Timer.StopTimer (TimerType.MemberLookup);
3173 list = MemberLookup_FindMembers (
3174 current_type, mt, bf, name, out used_cache);
3176 Timer.StartTimer (TimerType.MemberLookup);
3179 // When queried for an interface type, the cache will automatically check all
3180 // inherited members, so we don't need to do this here. However, this only
3181 // works if we already used the cache in the first iteration of this loop.
3183 // If we used the cache in any further iteration, we can still terminate the
3184 // loop since the cache always looks in all parent classes.
3190 skip_iface_check = false;
3192 if (current_type == TypeManager.object_type)
3195 current_type = current_type.BaseType;
3198 // This happens with interfaces, they have a null
3199 // basetype. Look members up in the Object class.
3201 if (current_type == null) {
3202 current_type = TypeManager.object_type;
3207 if (list.Length == 0)
3211 // Events and types are returned by both `static' and `instance'
3212 // searches, which means that our above FindMembers will
3213 // return two copies of the same.
3215 if (list.Length == 1 && !(list [0] is MethodBase)){
3220 // Multiple properties: we query those just to find out the indexer
3223 if (list [0] is PropertyInfo)
3227 // We found an event: the cache lookup returns both the event and
3228 // its private field.
3230 if (list [0] is EventInfo) {
3231 if ((list.Length == 2) && (list [1] is FieldInfo))
3232 return new MemberInfo [] { list [0] };
3239 // We found methods, turn the search into "method scan"
3243 if (first_members_list != null) {
3244 if (use_first_members_list) {
3245 method_list = CopyNewMethods (method_list, first_members_list);
3246 use_first_members_list = false;
3249 method_list = CopyNewMethods (method_list, list);
3251 first_members_list = list;
3252 use_first_members_list = true;
3254 mt &= (MemberTypes.Method | MemberTypes.Constructor);
3256 } while (searching);
3258 if (use_first_members_list) {
3259 foreach (MemberInfo mi in first_members_list) {
3260 if (! (mi is MethodBase)) {
3261 method_list = CopyNewMethods (method_list, first_members_list);
3262 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
3265 return (MemberInfo []) first_members_list;
3268 if (method_list != null && method_list.Count > 0) {
3269 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
3272 // This happens if we already used the cache in the first iteration, in this case
3273 // the cache already looked in all interfaces.
3275 if (skip_iface_check)
3279 // Interfaces do not list members they inherit, so we have to
3282 if (!queried_type.IsInterface)
3285 if (queried_type.IsArray)
3286 queried_type = TypeManager.array_type;
3288 Type [] ifaces = GetInterfaces (queried_type);
3292 foreach (Type itype in ifaces){
3295 x = MemberLookup (null, null, itype, mt, bf, name, null);
3303 // Tests whether external method is really special
3304 public static bool IsSpecialMethod (MethodBase mb)
3306 string name = mb.Name;
3307 if (name.StartsWith ("get_") || name.StartsWith ("set_"))
3308 return mb.DeclaringType.GetProperty (name.Substring (4)) != null;
3310 if (name.StartsWith ("add_"))
3311 return mb.DeclaringType.GetEvent (name.Substring (4)) != null;
3313 if (name.StartsWith ("remove_"))
3314 return mb.DeclaringType.GetEvent (name.Substring (7)) != null;
3316 if (name.StartsWith ("op_")){
3317 foreach (string oname in Unary.oper_names) {
3322 foreach (string oname in Binary.oper_names) {
3335 /// There is exactly one instance of this class per type.
3337 public sealed class TypeHandle : IMemberContainer {
3338 public readonly TypeHandle BaseType;
3340 readonly int id = ++next_id;
3341 static int next_id = 0;
3344 /// Lookup a TypeHandle instance for the given type. If the type doesn't have
3345 /// a TypeHandle yet, a new instance of it is created. This static method
3346 /// ensures that we'll only have one TypeHandle instance per type.
3348 public static TypeHandle GetTypeHandle (Type t)
3350 TypeHandle handle = (TypeHandle) type_hash [t];
3354 handle = new TypeHandle (t);
3355 type_hash.Add (t, handle);
3359 public static void CleanUp ()
3365 /// Returns the TypeHandle for TypeManager.object_type.
3367 public static IMemberContainer ObjectType {
3369 if (object_type != null)
3372 object_type = GetTypeHandle (TypeManager.object_type);
3379 /// Returns the TypeHandle for TypeManager.array_type.
3381 public static IMemberContainer ArrayType {
3383 if (array_type != null)
3386 array_type = GetTypeHandle (TypeManager.array_type);
3392 private static PtrHashtable type_hash = new PtrHashtable ();
3394 private static TypeHandle object_type = null;
3395 private static TypeHandle array_type = null;
3398 private string full_name;
3399 private bool is_interface;
3400 private MemberCache member_cache;
3402 private TypeHandle (Type type)
3405 full_name = type.FullName != null ? type.FullName : type.Name;
3406 if (type.BaseType != null)
3407 BaseType = GetTypeHandle (type.BaseType);
3408 this.is_interface = type.IsInterface || type.IsGenericParameter;
3409 this.member_cache = new MemberCache (this, true);
3412 // IMemberContainer methods
3414 public string Name {
3426 public IMemberContainer ParentContainer {
3432 public bool IsInterface {
3434 return is_interface;
3438 public MemberList GetMembers (MemberTypes mt, BindingFlags bf)
3440 MemberInfo [] members;
3441 if (type is GenericTypeParameterBuilder)
3442 return MemberList.Empty;
3443 if (mt == MemberTypes.Event)
3444 members = type.GetEvents (bf | BindingFlags.DeclaredOnly);
3446 members = type.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
3448 Array.Reverse (members);
3450 return new MemberList (members);
3453 // IMemberFinder methods
3455 public MemberList FindMembers (MemberTypes mt, BindingFlags bf, string name,
3456 MemberFilter filter, object criteria)
3458 return new MemberList (member_cache.FindMembers (mt, bf, name, filter, criteria));
3461 public MemberCache MemberCache {
3463 return member_cache;
3467 public override string ToString ()
3469 if (BaseType != null)
3470 return "TypeHandle (" + id + "," + Name + " : " + BaseType + ")";
3472 return "TypeHandle (" + id + "," + Name + ")";