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 obsolete_attribute_type;
89 static public Type conditional_attribute_type;
90 static public Type in_attribute_type;
91 static public Type cls_compliant_attribute_type;
92 static public Type typed_reference_type;
93 static public Type arg_iterator_type;
94 static public Type mbr_type;
95 static public Type struct_layout_attribute_type;
96 static public Type field_offset_attribute_type;
99 // An empty array of types
101 static public Type [] NoTypes;
102 static public TypeExpr [] NoTypeExprs;
106 // Expressions representing the internal types. Used during declaration
109 static public TypeExpr system_object_expr, system_string_expr;
110 static public TypeExpr system_boolean_expr, system_decimal_expr;
111 static public TypeExpr system_single_expr, system_double_expr;
112 static public TypeExpr system_sbyte_expr, system_byte_expr;
113 static public TypeExpr system_int16_expr, system_uint16_expr;
114 static public TypeExpr system_int32_expr, system_uint32_expr;
115 static public TypeExpr system_int64_expr, system_uint64_expr;
116 static public TypeExpr system_char_expr, system_void_expr;
117 static public TypeExpr system_asynccallback_expr;
118 static public TypeExpr system_iasyncresult_expr;
119 static public TypeExpr system_valuetype_expr;
122 // This is only used when compiling corlib
124 static public Type system_int32_type;
125 static public Type system_array_type;
126 static public Type system_type_type;
127 static public Type system_assemblybuilder_type;
128 static public MethodInfo system_int_array_get_length;
129 static public MethodInfo system_int_array_get_rank;
130 static public MethodInfo system_object_array_clone;
131 static public MethodInfo system_int_array_get_length_int;
132 static public MethodInfo system_int_array_get_lower_bound_int;
133 static public MethodInfo system_int_array_get_upper_bound_int;
134 static public MethodInfo system_void_array_copyto_array_int;
138 // Internal, not really used outside
140 static Type runtime_helpers_type;
143 // These methods are called by code generated by the compiler
145 static public MethodInfo string_concat_string_string;
146 static public MethodInfo string_concat_string_string_string;
147 static public MethodInfo string_concat_string_string_string_string;
148 static public MethodInfo string_concat_string_dot_dot_dot;
149 static public MethodInfo string_concat_object_object;
150 static public MethodInfo string_concat_object_object_object;
151 static public MethodInfo string_concat_object_dot_dot_dot;
152 static public MethodInfo string_isinterneted_string;
153 static public MethodInfo system_type_get_type_from_handle;
154 static public MethodInfo object_getcurrent_void;
155 static public MethodInfo bool_movenext_void;
156 static public MethodInfo ienumerable_getenumerator_void;
157 static public MethodInfo void_reset_void;
158 static public MethodInfo void_dispose_void;
159 static public MethodInfo void_monitor_enter_object;
160 static public MethodInfo void_monitor_exit_object;
161 static public MethodInfo void_initializearray_array_fieldhandle;
162 static public MethodInfo int_getlength_int;
163 static public MethodInfo delegate_combine_delegate_delegate;
164 static public MethodInfo delegate_remove_delegate_delegate;
165 static public MethodInfo int_get_offset_to_string_data;
166 static public MethodInfo int_array_get_length;
167 static public MethodInfo int_array_get_rank;
168 static public MethodInfo object_array_clone;
169 static public MethodInfo int_array_get_length_int;
170 static public MethodInfo int_array_get_lower_bound_int;
171 static public MethodInfo int_array_get_upper_bound_int;
172 static public MethodInfo void_array_copyto_array_int;
173 static public MethodInfo activator_create_instance;
176 // The attribute constructors.
178 static public ConstructorInfo object_ctor;
179 static public ConstructorInfo cons_param_array_attribute;
180 static public ConstructorInfo void_decimal_ctor_five_args;
181 static public ConstructorInfo unverifiable_code_ctor;
182 static public ConstructorInfo invalid_operation_ctor;
185 // Holds the Array of Assemblies that have been loaded
186 // (either because it is the default or the user used the
187 // -r command line option)
189 static Assembly [] assemblies;
192 // Keeps a list of modules. We used this to do lookups
193 // on the module using GetType -- needed for arrays
195 static Module [] modules;
198 // This is the type_cache from the assemblies to avoid
199 // hitting System.Reflection on every lookup.
201 static Hashtable types;
204 // This is used to hotld the corresponding TypeContainer objects
205 // since we need this in FindMembers
207 static Hashtable typecontainers;
210 // Keeps track of those types that are defined by the
213 static ArrayList user_types;
215 static PtrHashtable builder_to_declspace;
218 // Tracks the interfaces implemented by typebuilders. We only
219 // enter those who do implement or or more interfaces
221 static PtrHashtable builder_to_ifaces;
224 // Tracks the generic parameters.
226 static PtrHashtable builder_to_type_param;
229 // Maps MethodBase.RuntimeTypeHandle to a Type array that contains
230 // the arguments to the method
232 static Hashtable method_arguments;
235 // Maps PropertyBuilder to a Type array that contains
236 // the arguments to the indexer
238 static Hashtable indexer_arguments;
241 // Maybe `method_arguments' should be replaced and only
242 // method_internal_params should be kept?
244 static Hashtable method_internal_params;
247 // Keeps track of methods
250 static Hashtable builder_to_method;
253 // Contains all public types from referenced assemblies.
254 // This member is used only if CLS Compliance verification is required.
256 public static Hashtable all_imported_types;
263 public static void CleanUp ()
265 // Lets get everything clean so that we can collect before generating code
269 typecontainers = null;
271 builder_to_declspace = null;
272 builder_to_ifaces = null;
273 method_arguments = null;
274 indexer_arguments = null;
275 method_internal_params = null;
276 builder_to_method = null;
277 builder_to_type_param = null;
281 negative_hits = null;
282 builder_to_constant = null;
283 fieldbuilders_to_fields = null;
285 priv_fields_events = null;
288 TypeHandle.CleanUp ();
292 /// A filter for Findmembers that uses the Signature object to
295 static bool SignatureFilter (MemberInfo mi, object criteria)
297 Signature sig = (Signature) criteria;
299 if (!(mi is MethodBase))
302 if (mi.Name != sig.name)
305 int count = sig.args.Length;
307 if (mi is MethodBuilder || mi is ConstructorBuilder){
308 Type [] candidate_args = GetArgumentTypes ((MethodBase) mi);
310 if (candidate_args.Length != count)
313 for (int i = 0; i < count; i++)
314 if (candidate_args [i] != sig.args [i])
319 ParameterInfo [] pars = ((MethodBase) mi).GetParameters ();
321 if (pars.Length != count)
324 for (int i = 0; i < count; i++)
325 if (pars [i].ParameterType != sig.args [i])
331 // A delegate that points to the filter above.
332 static MemberFilter signature_filter;
335 // These are expressions that represent some of the internal data types, used
338 static void InitExpressionTypes ()
340 system_object_expr = new TypeLookupExpression ("System.Object");
341 system_string_expr = new TypeLookupExpression ("System.String");
342 system_boolean_expr = new TypeLookupExpression ("System.Boolean");
343 system_decimal_expr = new TypeLookupExpression ("System.Decimal");
344 system_single_expr = new TypeLookupExpression ("System.Single");
345 system_double_expr = new TypeLookupExpression ("System.Double");
346 system_sbyte_expr = new TypeLookupExpression ("System.SByte");
347 system_byte_expr = new TypeLookupExpression ("System.Byte");
348 system_int16_expr = new TypeLookupExpression ("System.Int16");
349 system_uint16_expr = new TypeLookupExpression ("System.UInt16");
350 system_int32_expr = new TypeLookupExpression ("System.Int32");
351 system_uint32_expr = new TypeLookupExpression ("System.UInt32");
352 system_int64_expr = new TypeLookupExpression ("System.Int64");
353 system_uint64_expr = new TypeLookupExpression ("System.UInt64");
354 system_char_expr = new TypeLookupExpression ("System.Char");
355 system_void_expr = new TypeLookupExpression ("System.Void");
356 system_asynccallback_expr = new TypeLookupExpression ("System.AsyncCallback");
357 system_iasyncresult_expr = new TypeLookupExpression ("System.IAsyncResult");
358 system_valuetype_expr = new TypeLookupExpression ("System.ValueType");
361 static TypeManager ()
363 assemblies = new Assembly [0];
365 user_types = new ArrayList ();
367 types = new Hashtable ();
368 typecontainers = new Hashtable ();
370 builder_to_declspace = new PtrHashtable ();
371 builder_to_method = new PtrHashtable ();
372 method_arguments = new PtrHashtable ();
373 method_internal_params = new PtrHashtable ();
374 indexer_arguments = new PtrHashtable ();
375 builder_to_ifaces = new PtrHashtable ();
376 builder_to_type_param = new PtrHashtable ();
378 NoTypes = new Type [0];
379 NoTypeExprs = new TypeExpr [0];
381 signature_filter = new MemberFilter (SignatureFilter);
382 InitExpressionTypes ();
385 public static void HandleDuplicate (string name, Type t)
387 Type prev = (Type) types [name];
388 TypeContainer tc = builder_to_declspace [prev] as TypeContainer;
392 // This probably never happens, as we catch this before
394 Report.Error (-17, "The type `" + name + "' has already been defined.");
398 tc = builder_to_declspace [t] as TypeContainer;
401 1595, "The type `" + name + "' is defined in an existing assembly;"+
402 " Using the new definition from: " + tc.Location);
405 1595, "The type `" + name + "' is defined in an existing assembly;");
408 Report.Warning (1595, "Previously defined in: " + prev.Assembly.FullName);
414 public static void AddUserType (string name, TypeBuilder t, TypeExpr[] ifaces)
419 HandleDuplicate (name, t);
424 builder_to_ifaces [t] = ifaces;
428 // This entry point is used by types that we define under the covers
430 public static void RegisterBuilder (TypeBuilder tb, TypeExpr [] ifaces)
433 builder_to_ifaces [tb] = ifaces;
436 public static void AddUserType (string name, TypeBuilder t, TypeContainer tc, TypeExpr [] ifaces)
438 builder_to_declspace.Add (t, tc);
439 typecontainers.Add (name, tc);
440 AddUserType (name, t, ifaces);
443 public static void AddDelegateType (string name, TypeBuilder t, Delegate del)
448 HandleDuplicate (name, t);
451 builder_to_declspace.Add (t, del);
454 public static void AddEnumType (string name, TypeBuilder t, Enum en)
459 HandleDuplicate (name, t);
461 builder_to_declspace.Add (t, en);
464 public static void AddUserInterface (string name, TypeBuilder t, Interface i, TypeExpr [] ifaces)
466 AddUserType (name, t, ifaces);
467 builder_to_declspace.Add (t, i);
470 public static void AddMethod (MethodBase builder, IMethodData method)
472 builder_to_method.Add (builder, method);
475 public static IMethodData GetMethod (MethodBase builder)
477 return (IMethodData) builder_to_method [builder];
480 public static void AddTypeParameter (Type t, TypeParameter tparam, TypeExpr[] ifaces)
482 if (!builder_to_type_param.Contains (t)) {
483 builder_to_type_param.Add (t, tparam);
486 builder_to_ifaces [t] = ifaces;
491 /// Returns the DeclSpace whose Type is `t' or null if there is no
492 /// DeclSpace for `t' (ie, the Type comes from a library)
494 public static DeclSpace LookupDeclSpace (Type t)
496 return builder_to_declspace [t] as DeclSpace;
500 /// Returns the TypeContainer whose Type is `t' or null if there is no
501 /// TypeContainer for `t' (ie, the Type comes from a library)
503 public static TypeContainer LookupTypeContainer (Type t)
505 return builder_to_declspace [t] as TypeContainer;
508 public static IMemberContainer LookupMemberContainer (Type t)
510 if (t is TypeBuilder) {
511 IMemberContainer container = builder_to_declspace [t] as IMemberContainer;
512 if (container != null)
516 if (t is GenericTypeParameterBuilder) {
517 IMemberContainer container = builder_to_type_param [t] as IMemberContainer;
519 if (container != null)
523 return TypeHandle.GetTypeHandle (t);
526 public static Interface LookupInterface (Type t)
528 return builder_to_declspace [t] as Interface;
531 public static Delegate LookupDelegate (Type t)
533 return builder_to_declspace [t] as Delegate;
536 public static Enum LookupEnum (Type t)
538 return builder_to_declspace [t] as Enum;
541 public static Class LookupClass (Type t)
543 return (Class) builder_to_declspace [t];
546 public static TypeParameter LookupTypeParameter (Type t)
548 return (TypeParameter) builder_to_type_param [t];
551 public static bool HasConstructorConstraint (Type t)
553 if (!t.IsGenericParameter)
554 throw new InvalidOperationException ();
556 TypeParameter tparam = LookupTypeParameter (t);
558 return tparam.HasConstructorConstraint;
560 object[] attrs = t.GetCustomAttributes (
561 TypeManager.new_constraint_attr_type, false);
563 return attrs.Length > 0;
568 /// Registers an assembly to load types from.
570 public static void AddAssembly (Assembly a)
572 foreach (Assembly assembly in assemblies) {
577 int top = assemblies.Length;
578 Assembly [] n = new Assembly [top + 1];
580 assemblies.CopyTo (n, 0);
586 public static Assembly [] GetAssemblies ()
592 /// Registers a module builder to lookup types from
594 public static void AddModule (Module mb)
596 int top = modules != null ? modules.Length : 0;
597 Module [] n = new Module [top + 1];
600 modules.CopyTo (n, 0);
605 public static Module[] Modules {
611 static Hashtable references = new Hashtable ();
614 // Gets the reference to T version of the Type (T&)
616 public static Type GetReferenceType (Type t)
618 return t.MakeByRefType ();
621 static Hashtable pointers = new Hashtable ();
624 // Gets the pointer to T version of the Type (T*)
626 public static Type GetPointerType (Type t)
628 string tname = t.FullName + "*";
630 Type ret = t.Assembly.GetType (tname);
633 // If the type comes from the assembly we are building
634 // We need the Hashtable, because .NET 1.1 will return different instance types
635 // every time we call ModuleBuilder.GetType.
638 if (pointers [t] == null)
639 pointers [t] = CodeGen.Module.Builder.GetType (tname);
641 ret = (Type) pointers [t];
648 // Low-level lookup, cache-less
650 static Type LookupTypeReflection (string name)
654 foreach (Assembly a in assemblies){
655 t = a.GetType (name);
660 TypeAttributes ta = t.Attributes & TypeAttributes.VisibilityMask;
661 if (ta == TypeAttributes.NotPublic ||
662 ta == TypeAttributes.NestedPrivate ||
663 ta == TypeAttributes.NestedAssembly ||
664 ta == TypeAttributes.NestedFamANDAssem){
667 // In .NET pointers turn out to be private, even if their
668 // element type is not
671 t = t.GetElementType ();
681 foreach (Module mb in modules) {
682 t = mb.GetType (name);
690 static Hashtable negative_hits = new Hashtable ();
693 // This function is used when you want to avoid the lookups, and want to go
694 // directly to the source. This will use the cache.
696 // Notice that bypassing the cache is bad, because on Microsoft.NET runtime
697 // GetType ("DynamicType[]") != GetType ("DynamicType[]"), and there is no
698 // way to test things other than doing a fullname compare
700 public static Type LookupTypeDirect (string name)
702 Type t = (Type) types [name];
706 t = LookupTypeReflection (name);
714 static readonly char [] dot_array = { '.' };
717 /// Returns the Type associated with @name, takes care of the fact that
718 /// reflection expects nested types to be separated from the main type
719 /// with a "+" instead of a "."
721 public static Type LookupType (string name)
726 // First lookup in user defined and cached values
729 t = (Type) types [name];
733 // Two thirds of the failures are caught here.
734 if (negative_hits.Contains (name))
737 // Sadly, split takes a param array, so this ends up allocating *EVERY TIME*
738 string [] elements = name.Split (dot_array);
739 int count = elements.Length;
741 for (int n = 1; n <= count; n++){
742 string top_level_type = String.Join (".", elements, 0, n);
744 // One third of the failures are caught here.
745 if (negative_hits.Contains (top_level_type))
748 t = (Type) types [top_level_type];
750 t = LookupTypeReflection (top_level_type);
752 negative_hits [top_level_type] = null;
763 // We know that System.Object does not have children, and since its the parent of
764 // all the objects, it always gets probbed for inner classes.
766 if (top_level_type == "System.Object")
769 string newt = top_level_type + "+" + String.Join ("+", elements, n, count - n);
770 //Console.WriteLine ("Looking up: " + newt + " " + name);
771 t = LookupTypeReflection (newt);
773 negative_hits [name] = null;
778 negative_hits [name] = null;
783 /// Computes the namespaces that we import from the assemblies we reference.
785 public static void ComputeNamespaces ()
787 MethodInfo assembly_get_namespaces = typeof (Assembly).GetMethod ("GetNamespaces", BindingFlags.Instance|BindingFlags.NonPublic);
790 // First add the assembly namespaces
792 if (assembly_get_namespaces != null){
793 int count = assemblies.Length;
795 for (int i = 0; i < count; i++){
796 Assembly a = assemblies [i];
797 string [] namespaces = (string []) assembly_get_namespaces.Invoke (a, null);
798 foreach (string ns in namespaces){
801 Namespace.LookupNamespace (ns, true);
805 Hashtable cache = new Hashtable ();
806 cache.Add ("", null);
807 foreach (Assembly a in assemblies) {
808 foreach (Type t in a.GetExportedTypes ()) {
809 string ns = t.Namespace;
810 if (ns == null || cache.Contains (ns))
813 Namespace.LookupNamespace (ns, true);
814 cache.Add (ns, null);
821 /// Fills static table with exported types from all referenced assemblies.
822 /// This information is required for CLS Compliance tests.
824 public static void LoadAllImportedTypes ()
826 if (!CodeGen.Assembly.IsClsCompliant)
829 all_imported_types = new Hashtable ();
830 foreach (Assembly a in assemblies) {
831 foreach (Type t in a.GetExportedTypes ()) {
832 all_imported_types [t.FullName] = t;
837 public static bool NamespaceClash (string name, Location loc)
839 if (Namespace.LookupNamespace (name, false) == null)
842 Report.Error (519, loc, String.Format ("`{0}' clashes with a predefined namespace", name));
847 /// Returns the C# name of a type if possible, or the full type name otherwise
849 static public string CSharpName (Type t)
851 if (t.FullName == null)
854 return Regex.Replace (t.FullName,
856 @"(Int32|UInt32|Int16|UInt16|Int64|UInt64|" +
857 @"Single|Double|Char|Decimal|Byte|SByte|Object|" +
858 @"Boolean|String|Void)" +
860 new MatchEvaluator (CSharpNameMatch));
863 static String CSharpNameMatch (Match match)
865 string s = match.Groups [1].Captures [0].Value;
867 Replace ("int32", "int").
868 Replace ("uint32", "uint").
869 Replace ("int16", "short").
870 Replace ("uint16", "ushort").
871 Replace ("int64", "long").
872 Replace ("uint64", "ulong").
873 Replace ("single", "float").
874 Replace ("boolean", "bool")
875 + match.Groups [2].Captures [0].Value;
879 /// Returns the signature of the method with full namespace classification
881 static public string GetFullNameSignature (MemberInfo mi)
883 return mi.DeclaringType.FullName.Replace ('+', '.') + '.' + mi.Name;
886 static public string GetFullNameSignature (MethodBase mb)
888 string name = mb.Name;
890 name = mb.DeclaringType.Name;
892 if (mb.IsSpecialName) {
893 if (name.StartsWith ("get_") || name.StartsWith ("set_")) {
894 name = name.Remove (0, 4);
901 return mb.DeclaringType.FullName.Replace ('+', '.') + '.' + name;
904 static public string GetFullName (Type t)
906 if (t.FullName == null)
909 string name = t.FullName.Replace ('+', '.');
911 DeclSpace tc = LookupDeclSpace (t);
912 if ((tc != null) && tc.IsGeneric) {
913 TypeParameter[] tparam = tc.TypeParameters;
915 StringBuilder sb = new StringBuilder (name);
917 for (int i = 0; i < tparam.Length; i++) {
920 sb.Append (tparam [i].Name);
923 return sb.ToString ();
924 } else if (t.HasGenericArguments && !t.IsGenericInstance) {
925 Type[] tparam = t.GetGenericArguments ();
927 StringBuilder sb = new StringBuilder (name);
929 for (int i = 0; i < tparam.Length; i++) {
932 sb.Append (tparam [i].Name);
935 return sb.ToString ();
942 /// Returns the signature of the property and indexer
944 static public string CSharpSignature (PropertyBuilder pb, bool is_indexer)
947 return GetFullNameSignature (pb);
950 MethodBase mb = pb.GetSetMethod (true) != null ? pb.GetSetMethod (true) : pb.GetGetMethod (true);
951 string signature = GetFullNameSignature (mb);
952 string arg = TypeManager.LookupParametersByBuilder (mb).ParameterDesc (0);
953 return String.Format ("{0}.this[{1}]", signature.Substring (0, signature.LastIndexOf ('.')), arg);
957 /// Returns the signature of the method
959 static public string CSharpSignature (MethodBase mb)
961 StringBuilder sig = new StringBuilder ("(");
964 // FIXME: We should really have a single function to do
965 // everything instead of the following 5 line pattern
967 ParameterData iparams = LookupParametersByBuilder (mb);
970 iparams = new ReflectionParameters (mb);
973 if (mb.IsSpecialName && iparams.Count == 0)
974 return GetFullNameSignature (mb);
976 for (int i = 0; i < iparams.Count; i++) {
980 sig.Append (iparams.ParameterDesc (i));
985 if (mb.IsSpecialName && iparams.Count == 1) {
986 sig.Replace ('(', '[');
987 sig.Replace (')', ']');
990 return GetFullNameSignature (mb) + sig.ToString ();
994 /// Looks up a type, and aborts if it is not found. This is used
995 /// by types required by the compiler
997 static Type CoreLookupType (string name)
999 Type t = LookupTypeDirect (name);
1002 Report.Error (518, "The predefined type `" + name + "' is not defined or imported");
1003 Environment.Exit (1);
1010 /// Returns the MethodInfo for a method named `name' defined
1011 /// in type `t' which takes arguments of types `args'
1013 static MethodInfo GetMethod (Type t, string name, Type [] args, bool is_private, bool report_errors)
1017 BindingFlags flags = instance_and_static | BindingFlags.Public;
1023 flags |= BindingFlags.NonPublic;
1025 list = FindMembers (t, MemberTypes.Method, flags, signature_filter, sig);
1026 if (list.Count == 0) {
1028 Report.Error (-19, "Can not find the core function `" + name + "'");
1032 MethodInfo mi = list [0] as MethodInfo;
1035 Report.Error (-19, "Can not find the core function `" + name + "'");
1042 static MethodInfo GetMethod (Type t, string name, Type [] args, bool report_errors)
1044 return GetMethod (t, name, args, false, report_errors);
1047 static MethodInfo GetMethod (Type t, string name, Type [] args)
1049 return GetMethod (t, name, args, true);
1054 /// Returns the ConstructorInfo for "args"
1056 static ConstructorInfo GetConstructor (Type t, Type [] args)
1064 list = FindMembers (t, MemberTypes.Constructor,
1065 instance_and_static | BindingFlags.Public | BindingFlags.DeclaredOnly,
1066 signature_filter, sig);
1067 if (list.Count == 0){
1068 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
1072 ConstructorInfo ci = list [0] as ConstructorInfo;
1074 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
1081 public static void InitEnumUnderlyingTypes ()
1084 int32_type = CoreLookupType ("System.Int32");
1085 int64_type = CoreLookupType ("System.Int64");
1086 uint32_type = CoreLookupType ("System.UInt32");
1087 uint64_type = CoreLookupType ("System.UInt64");
1088 byte_type = CoreLookupType ("System.Byte");
1089 sbyte_type = CoreLookupType ("System.SByte");
1090 short_type = CoreLookupType ("System.Int16");
1091 ushort_type = CoreLookupType ("System.UInt16");
1095 /// The types have to be initialized after the initial
1096 /// population of the type has happened (for example, to
1097 /// bootstrap the corlib.dll
1099 public static void InitCoreTypes ()
1101 object_type = CoreLookupType ("System.Object");
1102 value_type = CoreLookupType ("System.ValueType");
1104 InitEnumUnderlyingTypes ();
1106 char_type = CoreLookupType ("System.Char");
1107 string_type = CoreLookupType ("System.String");
1108 float_type = CoreLookupType ("System.Single");
1109 double_type = CoreLookupType ("System.Double");
1110 char_ptr_type = CoreLookupType ("System.Char*");
1111 decimal_type = CoreLookupType ("System.Decimal");
1112 bool_type = CoreLookupType ("System.Boolean");
1113 enum_type = CoreLookupType ("System.Enum");
1115 multicast_delegate_type = CoreLookupType ("System.MulticastDelegate");
1116 delegate_type = CoreLookupType ("System.Delegate");
1118 array_type = CoreLookupType ("System.Array");
1119 void_type = CoreLookupType ("System.Void");
1120 type_type = CoreLookupType ("System.Type");
1122 runtime_field_handle_type = CoreLookupType ("System.RuntimeFieldHandle");
1123 runtime_argument_handle_type = CoreLookupType ("System.RuntimeArgumentHandle");
1124 runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices.RuntimeHelpers");
1125 default_member_type = CoreLookupType ("System.Reflection.DefaultMemberAttribute");
1126 runtime_handle_type = CoreLookupType ("System.RuntimeTypeHandle");
1127 asynccallback_type = CoreLookupType ("System.AsyncCallback");
1128 iasyncresult_type = CoreLookupType ("System.IAsyncResult");
1129 ienumerator_type = CoreLookupType ("System.Collections.IEnumerator");
1130 ienumerable_type = CoreLookupType ("System.Collections.IEnumerable");
1131 idisposable_type = CoreLookupType ("System.IDisposable");
1132 icloneable_type = CoreLookupType ("System.ICloneable");
1133 iconvertible_type = CoreLookupType ("System.IConvertible");
1134 monitor_type = CoreLookupType ("System.Threading.Monitor");
1135 intptr_type = CoreLookupType ("System.IntPtr");
1137 attribute_type = CoreLookupType ("System.Attribute");
1138 attribute_usage_type = CoreLookupType ("System.AttributeUsageAttribute");
1139 dllimport_type = CoreLookupType ("System.Runtime.InteropServices.DllImportAttribute");
1140 methodimpl_attr_type = CoreLookupType ("System.Runtime.CompilerServices.MethodImplAttribute");
1141 marshal_as_attr_type = CoreLookupType ("System.Runtime.InteropServices.MarshalAsAttribute");
1142 new_constraint_attr_type = CoreLookupType ("System.Runtime.CompilerServices.NewConstraintAttribute");
1143 param_array_type = CoreLookupType ("System.ParamArrayAttribute");
1144 in_attribute_type = CoreLookupType ("System.Runtime.InteropServices.InAttribute");
1145 typed_reference_type = CoreLookupType ("System.TypedReference");
1146 arg_iterator_type = CoreLookupType ("System.ArgIterator");
1147 mbr_type = CoreLookupType ("System.MarshalByRefObject");
1150 // Sigh. Remove this before the release. Wonder what versions of Mono
1151 // people are running.
1153 guid_attr_type = LookupType ("System.Runtime.InteropServices.GuidAttribute");
1155 unverifiable_code_type= CoreLookupType ("System.Security.UnverifiableCodeAttribute");
1157 void_ptr_type = CoreLookupType ("System.Void*");
1159 indexer_name_type = CoreLookupType ("System.Runtime.CompilerServices.IndexerNameAttribute");
1161 exception_type = CoreLookupType ("System.Exception");
1162 activator_type = CoreLookupType ("System.Activator");
1163 invalid_operation_exception_type = CoreLookupType ("System.InvalidOperationException");
1168 obsolete_attribute_type = CoreLookupType ("System.ObsoleteAttribute");
1169 conditional_attribute_type = CoreLookupType ("System.Diagnostics.ConditionalAttribute");
1170 cls_compliant_attribute_type = CoreLookupType ("System.CLSCompliantAttribute");
1171 struct_layout_attribute_type = CoreLookupType ("System.Runtime.InteropServices.StructLayoutAttribute");
1172 field_offset_attribute_type = CoreLookupType ("System.Runtime.InteropServices.FieldOffsetAttribute");
1175 // When compiling corlib, store the "real" types here.
1177 if (!RootContext.StdLib) {
1178 system_int32_type = typeof (System.Int32);
1179 system_array_type = typeof (System.Array);
1180 system_type_type = typeof (System.Type);
1181 system_assemblybuilder_type = typeof (System.Reflection.Emit.AssemblyBuilder);
1183 Type [] void_arg = { };
1184 system_int_array_get_length = GetMethod (
1185 system_array_type, "get_Length", void_arg);
1186 system_int_array_get_rank = GetMethod (
1187 system_array_type, "get_Rank", void_arg);
1188 system_object_array_clone = GetMethod (
1189 system_array_type, "Clone", void_arg);
1191 Type [] system_int_arg = { system_int32_type };
1192 system_int_array_get_length_int = GetMethod (
1193 system_array_type, "GetLength", system_int_arg);
1194 system_int_array_get_upper_bound_int = GetMethod (
1195 system_array_type, "GetUpperBound", system_int_arg);
1196 system_int_array_get_lower_bound_int = GetMethod (
1197 system_array_type, "GetLowerBound", system_int_arg);
1199 Type [] system_array_int_arg = { system_array_type, system_int32_type };
1200 system_void_array_copyto_array_int = GetMethod (
1201 system_array_type, "CopyTo", system_array_int_arg);
1203 Type [] system_3_type_arg = {
1204 system_type_type, system_type_type, system_type_type };
1205 Type [] system_4_type_arg = {
1206 system_type_type, system_type_type, system_type_type, system_type_type };
1208 MethodInfo set_corlib_type_builders = GetMethod (
1209 system_assemblybuilder_type, "SetCorlibTypeBuilders",
1210 system_4_type_arg, true, false);
1212 if (set_corlib_type_builders != null) {
1213 object[] args = new object [4];
1214 args [0] = object_type;
1215 args [1] = value_type;
1216 args [2] = enum_type;
1217 args [3] = void_type;
1219 set_corlib_type_builders.Invoke (CodeGen.Assembly.Builder, args);
1221 // Compatibility for an older version of the class libs.
1222 set_corlib_type_builders = GetMethod (
1223 system_assemblybuilder_type, "SetCorlibTypeBuilders",
1224 system_3_type_arg, true, true);
1226 if (set_corlib_type_builders == null) {
1227 Report.Error (-26, "Corlib compilation is not supported in Microsoft.NET due to bugs in it");
1231 object[] args = new object [3];
1232 args [0] = object_type;
1233 args [1] = value_type;
1234 args [2] = enum_type;
1236 set_corlib_type_builders.Invoke (CodeGen.Assembly.Builder, args);
1240 system_object_expr.Type = object_type;
1241 system_string_expr.Type = string_type;
1242 system_boolean_expr.Type = bool_type;
1243 system_decimal_expr.Type = decimal_type;
1244 system_single_expr.Type = float_type;
1245 system_double_expr.Type = double_type;
1246 system_sbyte_expr.Type = sbyte_type;
1247 system_byte_expr.Type = byte_type;
1248 system_int16_expr.Type = short_type;
1249 system_uint16_expr.Type = ushort_type;
1250 system_int32_expr.Type = int32_type;
1251 system_uint32_expr.Type = uint32_type;
1252 system_int64_expr.Type = int64_type;
1253 system_uint64_expr.Type = uint64_type;
1254 system_char_expr.Type = char_type;
1255 system_void_expr.Type = void_type;
1256 system_asynccallback_expr.Type = asynccallback_type;
1257 system_iasyncresult_expr.Type = iasyncresult_type;
1258 system_valuetype_expr.Type = value_type;
1262 // The helper methods that are used by the compiler
1264 public static void InitCodeHelpers ()
1267 // Now load the default methods that we use.
1269 Type [] string_string = { string_type, string_type };
1270 string_concat_string_string = GetMethod (
1271 string_type, "Concat", string_string);
1272 Type [] string_string_string = { string_type, string_type, string_type };
1273 string_concat_string_string_string = GetMethod (
1274 string_type, "Concat", string_string_string);
1275 Type [] string_string_string_string = { string_type, string_type, string_type, string_type };
1276 string_concat_string_string_string_string = GetMethod (
1277 string_type, "Concat", string_string_string_string);
1278 Type[] params_string = { TypeManager.LookupType ("System.String[]") };
1279 string_concat_string_dot_dot_dot = GetMethod (
1280 string_type, "Concat", params_string);
1282 Type [] object_object = { object_type, object_type };
1283 string_concat_object_object = GetMethod (
1284 string_type, "Concat", object_object);
1285 Type [] object_object_object = { object_type, object_type, object_type };
1286 string_concat_object_object_object = GetMethod (
1287 string_type, "Concat", object_object_object);
1288 Type[] params_object = { TypeManager.LookupType ("System.Object[]") };
1289 string_concat_object_dot_dot_dot = GetMethod (
1290 string_type, "Concat", params_object);
1292 Type [] string_ = { string_type };
1293 string_isinterneted_string = GetMethod (
1294 string_type, "IsInterned", string_);
1296 Type [] runtime_type_handle = { runtime_handle_type };
1297 system_type_get_type_from_handle = GetMethod (
1298 type_type, "GetTypeFromHandle", runtime_type_handle);
1300 Type [] delegate_delegate = { delegate_type, delegate_type };
1301 delegate_combine_delegate_delegate = GetMethod (
1302 delegate_type, "Combine", delegate_delegate);
1304 delegate_remove_delegate_delegate = GetMethod (
1305 delegate_type, "Remove", delegate_delegate);
1310 Type [] void_arg = { };
1311 object_getcurrent_void = GetMethod (
1312 ienumerator_type, "get_Current", void_arg);
1313 bool_movenext_void = GetMethod (
1314 ienumerator_type, "MoveNext", void_arg);
1315 void_reset_void = GetMethod (
1316 ienumerator_type, "Reset", void_arg);
1317 void_dispose_void = GetMethod (
1318 idisposable_type, "Dispose", void_arg);
1319 int_get_offset_to_string_data = GetMethod (
1320 runtime_helpers_type, "get_OffsetToStringData", void_arg);
1321 int_array_get_length = GetMethod (
1322 array_type, "get_Length", void_arg);
1323 int_array_get_rank = GetMethod (
1324 array_type, "get_Rank", void_arg);
1325 ienumerable_getenumerator_void = GetMethod (
1326 ienumerable_type, "GetEnumerator", void_arg);
1331 Type [] int_arg = { int32_type };
1332 int_array_get_length_int = GetMethod (
1333 array_type, "GetLength", int_arg);
1334 int_array_get_upper_bound_int = GetMethod (
1335 array_type, "GetUpperBound", int_arg);
1336 int_array_get_lower_bound_int = GetMethod (
1337 array_type, "GetLowerBound", int_arg);
1340 // System.Array methods
1342 object_array_clone = GetMethod (
1343 array_type, "Clone", void_arg);
1344 Type [] array_int_arg = { array_type, int32_type };
1345 void_array_copyto_array_int = GetMethod (
1346 array_type, "CopyTo", array_int_arg);
1351 Type [] object_arg = { object_type };
1352 void_monitor_enter_object = GetMethod (
1353 monitor_type, "Enter", object_arg);
1354 void_monitor_exit_object = GetMethod (
1355 monitor_type, "Exit", object_arg);
1357 Type [] array_field_handle_arg = { array_type, runtime_field_handle_type };
1359 void_initializearray_array_fieldhandle = GetMethod (
1360 runtime_helpers_type, "InitializeArray", array_field_handle_arg);
1365 int_getlength_int = GetMethod (
1366 array_type, "GetLength", int_arg);
1369 // Decimal constructors
1371 Type [] dec_arg = { int32_type, int32_type, int32_type, bool_type, byte_type };
1372 void_decimal_ctor_five_args = GetConstructor (
1373 decimal_type, dec_arg);
1378 cons_param_array_attribute = GetConstructor (
1379 param_array_type, void_arg);
1381 unverifiable_code_ctor = GetConstructor (
1382 unverifiable_code_type, void_arg);
1385 // InvalidOperationException
1387 invalid_operation_ctor = GetConstructor (
1388 invalid_operation_exception_type, void_arg);
1392 object_ctor = GetConstructor (object_type, void_arg);
1395 Type [] type_arg = { type_type };
1396 activator_create_instance = GetMethod (
1397 activator_type, "CreateInstance", type_arg);
1400 const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance;
1403 /// This is the "old", non-cache based FindMembers() function. We cannot use
1404 /// the cache here because there is no member name argument.
1406 public static MemberList FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1407 MemberFilter filter, object criteria)
1409 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
1412 // `builder_to_declspace' contains all dynamic types.
1416 Timer.StartTimer (TimerType.FindMembers);
1417 list = decl.FindMembers (mt, bf, filter, criteria);
1418 Timer.StopTimer (TimerType.FindMembers);
1423 // We have to take care of arrays specially, because GetType on
1424 // a TypeBuilder array will return a Type, not a TypeBuilder,
1425 // and we can not call FindMembers on this type.
1427 if (t.IsSubclassOf (TypeManager.array_type))
1428 return new MemberList (TypeManager.array_type.FindMembers (mt, bf, filter, criteria));
1431 // Since FindMembers will not lookup both static and instance
1432 // members, we emulate this behaviour here.
1434 if ((bf & instance_and_static) == instance_and_static){
1435 MemberInfo [] i_members = t.FindMembers (
1436 mt, bf & ~BindingFlags.Static, filter, criteria);
1438 int i_len = i_members.Length;
1440 MemberInfo one = i_members [0];
1443 // If any of these are present, we are done!
1445 if ((one is Type) || (one is EventInfo) || (one is FieldInfo))
1446 return new MemberList (i_members);
1449 MemberInfo [] s_members = t.FindMembers (
1450 mt, bf & ~BindingFlags.Instance, filter, criteria);
1452 int s_len = s_members.Length;
1453 if (i_len > 0 || s_len > 0)
1454 return new MemberList (i_members, s_members);
1457 return new MemberList (i_members);
1459 return new MemberList (s_members);
1463 return new MemberList (t.FindMembers (mt, bf, filter, criteria));
1468 /// This method is only called from within MemberLookup. It tries to use the member
1469 /// cache if possible and falls back to the normal FindMembers if not. The `used_cache'
1470 /// flag tells the caller whether we used the cache or not. If we used the cache, then
1471 /// our return value will already contain all inherited members and the caller don't need
1472 /// to check base classes and interfaces anymore.
1474 private static MemberInfo [] MemberLookup_FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1475 string name, out bool used_cache)
1478 // We have to take care of arrays specially, because GetType on
1479 // a TypeBuilder array will return a Type, not a TypeBuilder,
1480 // and we can not call FindMembers on this type.
1482 if (t == TypeManager.array_type || t.IsSubclassOf (TypeManager.array_type)) {
1484 return TypeHandle.ArrayType.MemberCache.FindMembers (
1485 mt, bf, name, FilterWithClosure_delegate, null);
1489 // If this is a dynamic type, it's always in the `builder_to_declspace' hash table
1490 // and we can ask the DeclSpace for the MemberCache.
1492 if (t is TypeBuilder) {
1493 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
1494 MemberCache cache = decl.MemberCache;
1497 // If this DeclSpace has a MemberCache, use it.
1500 if (cache != null) {
1502 return cache.FindMembers (
1503 mt, bf, name, FilterWithClosure_delegate, null);
1506 // If there is no MemberCache, we need to use the "normal" FindMembers.
1507 // Note, this is a VERY uncommon route!
1510 Timer.StartTimer (TimerType.FindMembers);
1511 list = decl.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
1512 FilterWithClosure_delegate, name);
1513 Timer.StopTimer (TimerType.FindMembers);
1515 return (MemberInfo []) list;
1518 if (t is GenericTypeParameterBuilder) {
1519 TypeParameter tparam = (TypeParameter) builder_to_type_param [t];
1522 Timer.StartTimer (TimerType.FindMembers);
1523 list = tparam.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
1524 FilterWithClosure_delegate, name);
1525 Timer.StopTimer (TimerType.FindMembers);
1527 return (MemberInfo []) list;
1531 // This call will always succeed. There is exactly one TypeHandle instance per
1532 // type, TypeHandle.GetTypeHandle() will either return it or create a new one
1533 // if it didn't already exist.
1535 TypeHandle handle = TypeHandle.GetTypeHandle (t);
1538 return handle.MemberCache.FindMembers (mt, bf, name, FilterWithClosure_delegate, null);
1541 public static bool IsBuiltinType (Type t)
1543 if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
1544 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1545 t == char_type || t == short_type || t == decimal_type || t == bool_type ||
1546 t == sbyte_type || t == byte_type || t == ushort_type || t == void_type)
1552 public static bool IsBuiltinType (TypeContainer tc)
1554 return IsBuiltinType (tc.TypeBuilder);
1558 // This is like IsBuiltinType, but lacks decimal_type, we should also clean up
1559 // the pieces in the code where we use IsBuiltinType and special case decimal_type.
1561 public static bool IsCLRType (Type t)
1563 if (t == object_type || t == int32_type || t == uint32_type ||
1564 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1565 t == char_type || t == short_type || t == bool_type ||
1566 t == sbyte_type || t == byte_type || t == ushort_type)
1572 public static bool IsDelegateType (Type t)
1574 if (t.IsGenericInstance)
1575 t = t.GetGenericTypeDefinition ();
1577 if (t.IsSubclassOf (TypeManager.delegate_type))
1583 public static bool IsEnumType (Type t)
1585 if (t == TypeManager.enum_type || t.IsSubclassOf (TypeManager.enum_type))
1590 public static bool IsBuiltinOrEnum (Type t)
1592 if (IsBuiltinType (t))
1602 // Only a quick hack to get things moving, while real runtime support appears
1604 public static bool IsGeneric (Type t)
1606 DeclSpace ds = (DeclSpace) builder_to_declspace [t];
1608 return ds.IsGeneric;
1611 public static bool HasGenericArguments (Type t)
1613 return GetNumberOfTypeArguments (t) > 0;
1616 public static int GetNumberOfTypeArguments (Type t)
1618 DeclSpace tc = LookupDeclSpace (t);
1620 return tc.IsGeneric ? tc.CountTypeParameters : 0;
1622 return t.HasGenericArguments ? t.GetGenericArguments ().Length : 0;
1625 public static Type[] GetTypeArguments (Type t)
1627 DeclSpace tc = LookupDeclSpace (t);
1630 throw new InvalidOperationException ();
1632 TypeParameter[] tparam = tc.TypeParameters;
1633 Type[] ret = new Type [tparam.Length];
1634 for (int i = 0; i < tparam.Length; i++) {
1635 ret [i] = tparam [i].Type;
1636 if (ret [i] == null)
1637 throw new InternalErrorException ();
1642 return t.GetGenericArguments ();
1646 // Whether a type is unmanaged. This is used by the unsafe code (25.2)
1648 public static bool IsUnmanagedType (Type t)
1650 if (IsBuiltinType (t) && t != TypeManager.string_type)
1659 if (IsValueType (t)){
1660 if (t is TypeBuilder){
1661 TypeContainer tc = LookupTypeContainer (t);
1663 if (tc.Fields != null){
1664 foreach (Field f in tc.Fields){
1665 if (f.FieldBuilder.IsStatic)
1667 if (!IsUnmanagedType (f.FieldBuilder.FieldType))
1673 FieldInfo [] fields = t.GetFields ();
1675 foreach (FieldInfo f in fields){
1678 if (!IsUnmanagedType (f.FieldType))
1688 public static bool IsValueType (Type t)
1690 return t.IsGenericParameter || t.IsValueType;
1693 public static bool IsInterfaceType (Type t)
1695 Interface iface = builder_to_declspace [t] as Interface;
1703 public static bool IsEqualGenericType (Type a, Type b)
1705 if ((a is TypeBuilder) && a.IsGenericTypeDefinition && b.IsGenericInstance) {
1707 // `a' is a generic type definition's TypeBuilder and `b' is a
1708 // generic instance of the same type.
1714 // void Test (Stack<T> stack) { }
1717 // The first argument of `Test' will be the generic instance
1718 // "Stack<!0>" - which is the same type than the "Stack" TypeBuilder.
1720 if (a != b.GetGenericTypeDefinition ())
1723 Type[] aparams = a.GetGenericArguments ();
1724 Type[] bparams = b.GetGenericArguments ();
1726 if (aparams.Length != bparams.Length)
1729 for (int i = 0; i < aparams.Length; i++)
1730 if (!aparams [i].Equals (bparams [i]))
1739 public static bool IsEqual (Type a, Type b)
1744 return IsEqualGenericType (a, b);
1747 public static bool MayBecomeEqualGenericTypes (Type a, Type b)
1749 if (a.IsGenericParameter) {
1751 // If a is an array of a's type, they may never
1755 b = b.GetElementType ();
1761 // If b is a generic parameter or an actual type,
1762 // they may become equal:
1764 // class X<T,U> : I<T>, I<U>
1765 // class X<T> : I<T>, I<float>
1767 if (b.IsGenericParameter || !b.IsGenericInstance)
1771 // We're now comparing a type parameter with a
1772 // generic instance. They may become equal unless
1773 // the type parameter appears anywhere in the
1774 // generic instance:
1776 // class X<T,U> : I<T>, I<X<U>>
1777 // -> error because you could instanciate it as
1780 // class X<T> : I<T>, I<X<T>> -> ok
1783 Type[] bargs = GetTypeArguments (b);
1784 for (int i = 0; i < bargs.Length; i++) {
1785 if (a.Equals (bargs [i]))
1792 if (b.IsGenericParameter)
1793 return MayBecomeEqualGenericTypes (b, a);
1796 // At this point, neither a nor b are a type parameter.
1798 // If one of them is a generic instance, let
1799 // MayBecomeEqualGenericInstances() compare them (if the
1800 // other one is not a generic instance, they can never
1804 if (a.IsGenericInstance || b.IsGenericInstance)
1805 return MayBecomeEqualGenericInstances (a, b);
1808 // If both of them are arrays.
1811 if (a.IsArray && b.IsArray) {
1812 if (a.GetArrayRank () != b.GetArrayRank ())
1815 a = a.GetElementType ();
1816 b = b.GetElementType ();
1818 return MayBecomeEqualGenericTypes (a, b);
1822 // Ok, two ordinary types.
1825 return a.Equals (b);
1829 // Checks whether two generic instances may become equal for some
1830 // particular instantiation (26.3.1).
1832 public static bool MayBecomeEqualGenericInstances (Type a, Type b)
1834 if (!a.IsGenericInstance || !b.IsGenericInstance)
1836 if (a.GetGenericTypeDefinition () != b.GetGenericTypeDefinition ())
1839 Type[] aargs = GetTypeArguments (a);
1840 Type[] bargs = GetTypeArguments (b);
1842 if (aargs.Length != bargs.Length)
1845 for (int i = 0; i < aargs.Length; i++) {
1846 if (MayBecomeEqualGenericTypes (aargs [i], bargs [i]))
1853 public static bool IsSubclassOf (Type type, Type parent)
1855 if (type.IsGenericInstance && !parent.IsGenericInstance)
1856 type = type.GetGenericTypeDefinition ();
1858 return type.IsSubclassOf (parent);
1862 // Checks whether `type' is a subclass or nested child of `parent'.
1864 public static bool IsSubclassOrNestedChildOf (Type type, Type parent)
1867 if ((type == parent) || type.IsSubclassOf (parent) ||
1868 IsEqualGenericType (type, parent))
1871 // Handle nested types.
1872 type = type.DeclaringType;
1873 } while (type != null);
1879 // Checks whether `type' is a nested child of `parent'.
1881 public static bool IsNestedChildOf (Type type, Type parent)
1886 type = type.DeclaringType;
1887 while (type != null) {
1891 type = type.DeclaringType;
1898 // Do the right thing when returning the element type of an
1899 // array type based on whether we are compiling corlib or not
1901 public static Type GetElementType (Type t)
1903 if (RootContext.StdLib)
1904 return t.GetElementType ();
1906 return TypeToCoreType (t.GetElementType ());
1910 /// Returns the User Defined Types
1912 public static ArrayList UserTypes {
1918 public static Hashtable TypeContainers {
1920 return typecontainers;
1924 static Hashtable builder_to_constant;
1926 public static void RegisterConstant (FieldBuilder fb, Const c)
1928 if (builder_to_constant == null)
1929 builder_to_constant = new PtrHashtable ();
1931 if (builder_to_constant.Contains (fb))
1934 builder_to_constant.Add (fb, c);
1937 public static Const LookupConstant (FieldBuilder fb)
1939 if (builder_to_constant == null)
1942 return (Const) builder_to_constant [fb];
1946 /// Gigantic work around for missing features in System.Reflection.Emit follows.
1950 /// Since System.Reflection.Emit can not return MethodBase.GetParameters
1951 /// for anything which is dynamic, and we need this in a number of places,
1952 /// we register this information here, and use it afterwards.
1954 static public bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] args)
1959 method_arguments.Add (mb, args);
1960 method_internal_params.Add (mb, ip);
1965 static public InternalParameters LookupParametersByBuilder (MethodBase mb)
1967 if (! (mb is ConstructorBuilder || mb is MethodBuilder))
1970 if (method_internal_params.Contains (mb))
1971 return (InternalParameters) method_internal_params [mb];
1973 throw new Exception ("Argument for Method not registered" + mb);
1977 /// Returns the argument types for a method based on its methodbase
1979 /// For dynamic methods, we use the compiler provided types, for
1980 /// methods from existing assemblies we load them from GetParameters,
1981 /// and insert them into the cache
1983 static public Type [] GetArgumentTypes (MethodBase mb)
1985 if (method_arguments.Contains (mb))
1986 return (Type []) method_arguments [mb];
1988 ParameterInfo [] pi = mb.GetParameters ();
1990 Type [] types = new Type [c];
1992 for (int i = 0; i < c; i++)
1993 types [i] = pi [i].ParameterType;
1995 method_arguments.Add (mb, types);
2001 /// Returns the argument types for an indexer based on its PropertyInfo
2003 /// For dynamic indexers, we use the compiler provided types, for
2004 /// indexers from existing assemblies we load them from GetParameters,
2005 /// and insert them into the cache
2007 static public Type [] GetArgumentTypes (PropertyInfo indexer)
2009 if (indexer_arguments.Contains (indexer))
2010 return (Type []) indexer_arguments [indexer];
2011 else if (indexer is PropertyBuilder)
2012 // If we're a PropertyBuilder and not in the
2013 // `indexer_arguments' hash, then we're a property and
2017 ParameterInfo [] pi = indexer.GetIndexParameters ();
2018 // Property, not an indexer.
2022 Type [] types = new Type [c];
2024 for (int i = 0; i < c; i++)
2025 types [i] = pi [i].ParameterType;
2027 indexer_arguments.Add (indexer, types);
2033 // This is a workaround the fact that GetValue is not
2034 // supported for dynamic types
2036 static Hashtable fields = new Hashtable ();
2037 static public bool RegisterFieldValue (FieldBuilder fb, object value)
2039 if (fields.Contains (fb))
2042 fields.Add (fb, value);
2047 static public object GetValue (FieldBuilder fb)
2052 static Hashtable fieldbuilders_to_fields = new Hashtable ();
2053 static public bool RegisterFieldBase (FieldBuilder fb, FieldBase f)
2055 if (fieldbuilders_to_fields.Contains (fb))
2058 fieldbuilders_to_fields.Add (fb, f);
2063 // The return value can be null; This will be the case for
2064 // auxiliary FieldBuilders created by the compiler that have no
2065 // real field being declared on the source code
2067 static public FieldBase GetField (FieldInfo fb)
2069 return (FieldBase) fieldbuilders_to_fields [fb];
2072 static Hashtable events;
2074 static public bool RegisterEvent (MyEventBuilder eb, MethodBase add, MethodBase remove)
2077 events = new Hashtable ();
2079 if (events.Contains (eb))
2082 events.Add (eb, new Pair (add, remove));
2087 static public MethodInfo GetAddMethod (EventInfo ei)
2089 if (ei is MyEventBuilder) {
2090 Pair pair = (Pair) events [ei];
2092 return (MethodInfo) pair.First;
2094 return ei.GetAddMethod ();
2097 static public MethodInfo GetRemoveMethod (EventInfo ei)
2099 if (ei is MyEventBuilder) {
2100 Pair pair = (Pair) events [ei];
2102 return (MethodInfo) pair.Second;
2104 return ei.GetRemoveMethod ();
2107 static Hashtable priv_fields_events;
2109 static public bool RegisterPrivateFieldOfEvent (EventInfo einfo, FieldBuilder builder)
2111 if (priv_fields_events == null)
2112 priv_fields_events = new Hashtable ();
2114 if (priv_fields_events.Contains (einfo))
2117 priv_fields_events.Add (einfo, builder);
2122 static public MemberInfo GetPrivateFieldOfEvent (EventInfo ei)
2124 if (priv_fields_events == null)
2127 return (MemberInfo) priv_fields_events [ei];
2130 static Hashtable properties;
2132 static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set)
2134 if (properties == null)
2135 properties = new Hashtable ();
2137 if (properties.Contains (pb))
2140 properties.Add (pb, new Pair (get, set));
2145 static public bool RegisterIndexer (PropertyBuilder pb, MethodBase get,
2146 MethodBase set, Type[] args)
2148 if (!RegisterProperty (pb, get,set))
2151 indexer_arguments.Add (pb, args);
2156 public static bool CheckStructCycles (TypeContainer tc, Hashtable seen)
2158 Hashtable hash = new Hashtable ();
2159 return CheckStructCycles (tc, seen, hash);
2162 public static bool CheckStructCycles (TypeContainer tc, Hashtable seen,
2165 if (!(tc is Struct) || IsBuiltinType (tc))
2169 // `seen' contains all types we've already visited.
2171 if (seen.Contains (tc))
2173 seen.Add (tc, null);
2175 if (tc.Fields == null)
2178 foreach (Field field in tc.Fields) {
2179 if (field.FieldBuilder.IsStatic)
2182 Type ftype = field.FieldBuilder.FieldType;
2183 TypeContainer ftc = LookupTypeContainer (ftype);
2187 if (hash.Contains (ftc)) {
2188 Report.Error (523, tc.Location,
2189 "Struct member `{0}.{1}' of type `{2}' " +
2190 "causes a cycle in the struct layout",
2191 tc.Name, field.Name, ftc.Name);
2196 // `hash' contains all types in the current path.
2198 hash.Add (tc, null);
2200 bool ok = CheckStructCycles (ftc, seen, hash);
2207 if (!seen.Contains (ftc))
2208 seen.Add (ftc, null);
2215 /// Given an array of interface types, expand and eliminate repeated ocurrences
2216 /// of an interface.
2220 /// This expands in context like: IA; IB : IA; IC : IA, IB; the interface "IC" to
2223 public static TypeExpr[] ExpandInterfaces (TypeExpr [] base_interfaces)
2225 ArrayList new_ifaces = new ArrayList ();
2227 foreach (TypeExpr iface in base_interfaces){
2228 if (!new_ifaces.Contains (iface))
2229 new_ifaces.Add (iface);
2231 TypeExpr [] implementing = iface.GetInterfaces ();
2233 foreach (TypeExpr imp in implementing){
2234 if (!new_ifaces.Contains (imp))
2235 new_ifaces.Add (imp);
2238 TypeExpr [] ret = new TypeExpr [new_ifaces.Count];
2239 new_ifaces.CopyTo (ret, 0);
2243 static PtrHashtable iface_cache = new PtrHashtable ();
2246 /// This function returns the interfaces in the type `t'. Works with
2247 /// both types and TypeBuilders.
2249 public static TypeExpr [] GetInterfaces (Type t)
2252 TypeExpr [] cached = iface_cache [t] as TypeExpr [];
2257 // The reason for catching the Array case is that Reflection.Emit
2258 // will not return a TypeBuilder for Array types of TypeBuilder types,
2259 // but will still throw an exception if we try to call GetInterfaces
2262 // Since the array interfaces are always constant, we return those for
2267 t = TypeManager.array_type;
2269 if (t is TypeBuilder){
2270 TypeExpr [] parent_ifaces;
2272 if (t.BaseType == null)
2273 parent_ifaces = NoTypeExprs;
2275 parent_ifaces = GetInterfaces (t.BaseType);
2276 TypeExpr [] type_ifaces = (TypeExpr []) builder_to_ifaces [t];
2277 if (type_ifaces == null)
2278 type_ifaces = NoTypeExprs;
2280 int parent_count = parent_ifaces.Length;
2281 TypeExpr [] result = new TypeExpr [parent_count + type_ifaces.Length];
2282 parent_ifaces.CopyTo (result, 0);
2283 type_ifaces.CopyTo (result, parent_count);
2285 iface_cache [t] = result;
2287 } else if (t is GenericTypeParameterBuilder){
2288 TypeExpr[] type_ifaces = (TypeExpr []) builder_to_ifaces [t];
2289 if (type_ifaces == null)
2290 type_ifaces = NoTypeExprs;
2292 iface_cache [t] = type_ifaces;
2295 Type [] ifaces = t.GetInterfaces ();
2296 if (ifaces.Length == 0)
2299 TypeExpr [] result = new TypeExpr [ifaces.Length];
2300 for (int i = 0; i < ifaces.Length; i++)
2301 result [i] = new TypeExpression (ifaces [i], Location.Null);
2303 iface_cache [t] = result;
2309 // gets the interfaces that are declared explicitly on t
2311 public static TypeExpr [] GetExplicitInterfaces (TypeBuilder t)
2313 return (TypeExpr []) builder_to_ifaces [t];
2317 /// The following is used to check if a given type implements an interface.
2318 /// The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
2320 public static bool ImplementsInterface (Type t, Type iface)
2322 TypeExpr [] interfaces;
2325 // FIXME OPTIMIZATION:
2326 // as soon as we hit a non-TypeBuiler in the interface
2327 // chain, we could return, as the `Type.GetInterfaces'
2328 // will return all the interfaces implement by the type
2332 interfaces = GetInterfaces (t);
2334 if (interfaces != null){
2335 foreach (TypeExpr i in interfaces){
2336 if (i.Type == iface)
2342 } while (t != null);
2347 static NumberFormatInfo nf_provider = CultureInfo.CurrentCulture.NumberFormat;
2349 // This is a custom version of Convert.ChangeType() which works
2350 // with the TypeBuilder defined types when compiling corlib.
2351 public static object ChangeType (object value, Type conversionType, out bool error)
2353 IConvertible convert_value = value as IConvertible;
2355 if (convert_value == null){
2361 // We must use Type.Equals() here since `conversionType' is
2362 // the TypeBuilder created version of a system type and not
2363 // the system type itself. You cannot use Type.GetTypeCode()
2364 // on such a type - it'd always return TypeCode.Object.
2368 if (conversionType.Equals (typeof (Boolean)))
2369 return (object)(convert_value.ToBoolean (nf_provider));
2370 else if (conversionType.Equals (typeof (Byte)))
2371 return (object)(convert_value.ToByte (nf_provider));
2372 else if (conversionType.Equals (typeof (Char)))
2373 return (object)(convert_value.ToChar (nf_provider));
2374 else if (conversionType.Equals (typeof (DateTime)))
2375 return (object)(convert_value.ToDateTime (nf_provider));
2376 else if (conversionType.Equals (typeof (Decimal)))
2377 return (object)(convert_value.ToDecimal (nf_provider));
2378 else if (conversionType.Equals (typeof (Double)))
2379 return (object)(convert_value.ToDouble (nf_provider));
2380 else if (conversionType.Equals (typeof (Int16)))
2381 return (object)(convert_value.ToInt16 (nf_provider));
2382 else if (conversionType.Equals (typeof (Int32)))
2383 return (object)(convert_value.ToInt32 (nf_provider));
2384 else if (conversionType.Equals (typeof (Int64)))
2385 return (object)(convert_value.ToInt64 (nf_provider));
2386 else if (conversionType.Equals (typeof (SByte)))
2387 return (object)(convert_value.ToSByte (nf_provider));
2388 else if (conversionType.Equals (typeof (Single)))
2389 return (object)(convert_value.ToSingle (nf_provider));
2390 else if (conversionType.Equals (typeof (String)))
2391 return (object)(convert_value.ToString (nf_provider));
2392 else if (conversionType.Equals (typeof (UInt16)))
2393 return (object)(convert_value.ToUInt16 (nf_provider));
2394 else if (conversionType.Equals (typeof (UInt32)))
2395 return (object)(convert_value.ToUInt32 (nf_provider));
2396 else if (conversionType.Equals (typeof (UInt64)))
2397 return (object)(convert_value.ToUInt64 (nf_provider));
2398 else if (conversionType.Equals (typeof (Object)))
2399 return (object)(value);
2409 // This is needed, because enumerations from assemblies
2410 // do not report their underlyingtype, but they report
2413 public static Type EnumToUnderlying (Type t)
2415 if (t == TypeManager.enum_type)
2418 t = t.UnderlyingSystemType;
2419 if (!TypeManager.IsEnumType (t))
2422 if (t is TypeBuilder) {
2423 // slow path needed to compile corlib
2424 if (t == TypeManager.bool_type ||
2425 t == TypeManager.byte_type ||
2426 t == TypeManager.sbyte_type ||
2427 t == TypeManager.char_type ||
2428 t == TypeManager.short_type ||
2429 t == TypeManager.ushort_type ||
2430 t == TypeManager.int32_type ||
2431 t == TypeManager.uint32_type ||
2432 t == TypeManager.int64_type ||
2433 t == TypeManager.uint64_type)
2435 throw new Exception ("Unhandled typecode in enum " + " from " + t.AssemblyQualifiedName);
2437 TypeCode tc = Type.GetTypeCode (t);
2440 case TypeCode.Boolean:
2441 return TypeManager.bool_type;
2443 return TypeManager.byte_type;
2444 case TypeCode.SByte:
2445 return TypeManager.sbyte_type;
2447 return TypeManager.char_type;
2448 case TypeCode.Int16:
2449 return TypeManager.short_type;
2450 case TypeCode.UInt16:
2451 return TypeManager.ushort_type;
2452 case TypeCode.Int32:
2453 return TypeManager.int32_type;
2454 case TypeCode.UInt32:
2455 return TypeManager.uint32_type;
2456 case TypeCode.Int64:
2457 return TypeManager.int64_type;
2458 case TypeCode.UInt64:
2459 return TypeManager.uint64_type;
2461 throw new Exception ("Unhandled typecode in enum " + tc + " from " + t.AssemblyQualifiedName);
2465 // When compiling corlib and called with one of the core types, return
2466 // the corresponding typebuilder for that type.
2468 public static Type TypeToCoreType (Type t)
2470 if (RootContext.StdLib || (t is TypeBuilder))
2473 TypeCode tc = Type.GetTypeCode (t);
2476 case TypeCode.Boolean:
2477 return TypeManager.bool_type;
2479 return TypeManager.byte_type;
2480 case TypeCode.SByte:
2481 return TypeManager.sbyte_type;
2483 return TypeManager.char_type;
2484 case TypeCode.Int16:
2485 return TypeManager.short_type;
2486 case TypeCode.UInt16:
2487 return TypeManager.ushort_type;
2488 case TypeCode.Int32:
2489 return TypeManager.int32_type;
2490 case TypeCode.UInt32:
2491 return TypeManager.uint32_type;
2492 case TypeCode.Int64:
2493 return TypeManager.int64_type;
2494 case TypeCode.UInt64:
2495 return TypeManager.uint64_type;
2496 case TypeCode.Single:
2497 return TypeManager.float_type;
2498 case TypeCode.Double:
2499 return TypeManager.double_type;
2500 case TypeCode.String:
2501 return TypeManager.string_type;
2503 if (t == typeof (void))
2504 return TypeManager.void_type;
2505 if (t == typeof (object))
2506 return TypeManager.object_type;
2507 if (t == typeof (System.Type))
2508 return TypeManager.type_type;
2509 if (t == typeof (System.IntPtr))
2510 return TypeManager.intptr_type;
2516 /// Utility function that can be used to probe whether a type
2517 /// is managed or not.
2519 public static bool VerifyUnManaged (Type t, Location loc)
2521 if (t.IsValueType || t.IsPointer){
2523 // FIXME: this is more complex, we actually need to
2524 // make sure that the type does not contain any
2530 if (!RootContext.StdLib && (t == TypeManager.decimal_type))
2531 // We need this explicit check here to make it work when
2532 // compiling corlib.
2537 "Cannot take the address or size of a variable of a managed type ('" +
2538 CSharpName (t) + "')");
2543 /// Returns the name of the indexer in a given type.
2546 /// The default is not always `Item'. The user can change this behaviour by
2547 /// using the DefaultMemberAttribute in the class.
2549 /// For example, the String class indexer is named `Chars' not `Item'
2551 public static string IndexerPropertyName (Type t)
2553 if (t.IsGenericInstance)
2554 t = t.GetGenericTypeDefinition ();
2556 if (t is TypeBuilder) {
2557 if (t.IsInterface) {
2558 Interface i = LookupInterface (t);
2560 if ((i == null) || (i.IndexerName == null))
2563 return i.IndexerName;
2565 TypeContainer tc = LookupTypeContainer (t);
2567 if ((tc == null) || (tc.IndexerName == null))
2570 return tc.IndexerName;
2574 System.Attribute attr = System.Attribute.GetCustomAttribute (
2575 t, TypeManager.default_member_type);
2577 DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
2578 return dma.MemberName;
2584 static MethodInfo pinned_method = null;
2585 public static void MakePinned (LocalBuilder builder)
2587 if (pinned_method == null) {
2588 pinned_method = typeof (LocalBuilder).GetMethod ("MakePinned", BindingFlags.Instance | BindingFlags.NonPublic);
2589 if (pinned_method == null) {
2590 Report.Warning (-24, new Location (-1), "Microsoft.NET does not support making pinned variables." +
2591 "This code may cause errors on a runtime with a moving GC");
2597 pinned_method.Invoke (builder, null);
2602 // Returns whether the array of memberinfos contains the given method
2604 public static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method)
2606 Type [] new_args = TypeManager.GetArgumentTypes (new_method);
2608 foreach (MethodBase method in array) {
2609 if (method.Name != new_method.Name)
2612 if (method is MethodInfo && new_method is MethodInfo)
2613 if (((MethodInfo) method).ReturnType != ((MethodInfo) new_method).ReturnType)
2617 Type [] old_args = TypeManager.GetArgumentTypes (method);
2618 int old_count = old_args.Length;
2621 if (new_args.Length != old_count)
2624 for (i = 0; i < old_count; i++){
2625 if (old_args [i] != new_args [i])
2638 // We copy methods from `new_members' into `target_list' if the signature
2639 // for the method from in the new list does not exist in the target_list
2641 // The name is assumed to be the same.
2643 public static ArrayList CopyNewMethods (ArrayList target_list, IList new_members)
2645 if (target_list == null){
2646 target_list = new ArrayList ();
2648 foreach (MemberInfo mi in new_members){
2649 if (mi is MethodBase)
2650 target_list.Add (mi);
2655 MemberInfo [] target_array = new MemberInfo [target_list.Count];
2656 target_list.CopyTo (target_array, 0);
2658 foreach (MemberInfo mi in new_members){
2659 MethodBase new_method = (MethodBase) mi;
2661 if (!ArrayContainsMethod (target_array, new_method))
2662 target_list.Add (new_method);
2667 static public bool IsGenericMethod (MethodBase mb)
2669 if (mb.DeclaringType is TypeBuilder) {
2670 IMethodData method = (IMethodData) builder_to_method [mb];
2674 return method.GenericMethod != null;
2677 return mb.IsGenericMethodDefinition;
2680 #region MemberLookup implementation
2683 // Whether we allow private members in the result (since FindMembers
2684 // uses NonPublic for both protected and private), we need to distinguish.
2687 static internal bool FilterNone (MemberInfo m, object filter_criteria)
2692 internal class Closure {
2693 internal bool private_ok;
2695 // Who is invoking us and which type is being queried currently.
2696 internal Type invocation_type;
2697 internal Type qualifier_type;
2699 // The assembly that defines the type is that is calling us
2700 internal Assembly invocation_assembly;
2701 internal IList almost_match;
2703 private bool CheckValidFamilyAccess (bool is_static, MemberInfo m)
2705 if (invocation_type == null)
2708 Debug.Assert (IsSubclassOrNestedChildOf (invocation_type, m.DeclaringType));
2713 // A nested class has access to all the protected members visible to its parent.
2714 if (qualifier_type != null
2715 && TypeManager.IsNestedChildOf (invocation_type, qualifier_type))
2718 if (invocation_type == m.DeclaringType
2719 || invocation_type.IsSubclassOf (m.DeclaringType)) {
2720 // Although a derived class can access protected members of its base class
2721 // it cannot do so through an instance of the base class (CS1540).
2722 // => Ancestry should be: declaring_type ->* invocation_type ->* qualified_type
2723 if (qualifier_type == null
2724 || qualifier_type == invocation_type
2725 || qualifier_type.IsSubclassOf (invocation_type))
2729 if (almost_match != null)
2730 almost_match.Add (m);
2735 // This filter filters by name + whether it is ok to include private
2736 // members in the search
2738 internal bool Filter (MemberInfo m, object filter_criteria)
2741 // Hack: we know that the filter criteria will always be in the `closure'
2745 if ((filter_criteria != null) && (m.Name != (string) filter_criteria))
2748 if (((qualifier_type == null) || (qualifier_type == invocation_type)) &&
2749 (invocation_type != null) && IsEqual (m.DeclaringType, invocation_type))
2753 // Ugly: we need to find out the type of `m', and depending
2754 // on this, tell whether we accept or not
2756 if (m is MethodBase){
2757 MethodBase mb = (MethodBase) m;
2758 MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
2760 if (ma == MethodAttributes.Private)
2761 return private_ok ||
2762 IsEqual (invocation_type, m.DeclaringType) ||
2763 IsNestedChildOf (invocation_type, m.DeclaringType);
2766 // FamAndAssem requires that we not only derivate, but we are on the
2769 if (ma == MethodAttributes.FamANDAssem){
2770 if (invocation_assembly != mb.DeclaringType.Assembly)
2774 // Assembly and FamORAssem succeed if we're in the same assembly.
2775 if ((ma == MethodAttributes.Assembly) || (ma == MethodAttributes.FamORAssem)){
2776 if (invocation_assembly == mb.DeclaringType.Assembly)
2780 // We already know that we aren't in the same assembly.
2781 if (ma == MethodAttributes.Assembly)
2784 // Family and FamANDAssem require that we derive.
2785 if ((ma == MethodAttributes.Family) || (ma == MethodAttributes.FamANDAssem)){
2786 if (invocation_type == null)
2789 if (!IsSubclassOrNestedChildOf (invocation_type, mb.DeclaringType))
2792 // Although a derived class can access protected members of its base class
2793 // it cannot do so through an instance of the base class (CS1540).
2794 if (!mb.IsStatic && (invocation_type != qualifier_type) &&
2795 (qualifier_type != null) &&
2796 invocation_type.IsSubclassOf (qualifier_type) &&
2797 !TypeManager.IsNestedChildOf (invocation_type, qualifier_type))
2807 if (m is FieldInfo){
2808 FieldInfo fi = (FieldInfo) m;
2809 FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask;
2811 if (fa == FieldAttributes.Private)
2812 return private_ok ||
2813 IsEqual (invocation_type, m.DeclaringType) ||
2814 IsNestedChildOf (invocation_type, m.DeclaringType);
2817 // FamAndAssem requires that we not only derivate, but we are on the
2820 if (fa == FieldAttributes.FamANDAssem){
2821 if (invocation_assembly != fi.DeclaringType.Assembly)
2825 // Assembly and FamORAssem succeed if we're in the same assembly.
2826 if ((fa == FieldAttributes.Assembly) || (fa == FieldAttributes.FamORAssem)){
2827 if (invocation_assembly == fi.DeclaringType.Assembly)
2831 // We already know that we aren't in the same assembly.
2832 if (fa == FieldAttributes.Assembly)
2835 // Family and FamANDAssem require that we derive.
2836 if ((fa == FieldAttributes.Family) || (fa == FieldAttributes.FamANDAssem)){
2837 if (invocation_type == null)
2840 if (!IsSubclassOrNestedChildOf (invocation_type, fi.DeclaringType))
2843 // Although a derived class can access protected members of its base class
2844 // it cannot do so through an instance of the base class (CS1540).
2845 if (!fi.IsStatic && (invocation_type != qualifier_type) &&
2846 (qualifier_type != null) &&
2847 invocation_type.IsSubclassOf (qualifier_type) &&
2848 !TypeManager.IsNestedChildOf (invocation_type, qualifier_type))
2859 // EventInfos and PropertyInfos, return true because they lack permission
2860 // information, so we need to check later on the methods.
2866 static Closure closure = new Closure ();
2867 static MemberFilter FilterWithClosure_delegate = new MemberFilter (closure.Filter);
2868 static MemberFilter FilterNone_delegate = new MemberFilter (FilterNone);
2871 // Looks up a member called `name' in the `queried_type'. This lookup
2872 // is done by code that is contained in the definition for `invocation_type'
2873 // through a qualifier of type `qualifier_type' (or null if there is no qualifier).
2875 // `invocation_type' is used to check whether we're allowed to access the requested
2876 // member wrt its protection level.
2878 // When called from MemberAccess, `qualifier_type' is the type which is used to access
2879 // the requested member (`class B { A a = new A (); a.foo = 5; }'; here invocation_type
2880 // is B and qualifier_type is A). This is used to do the CS1540 check.
2882 // When resolving a SimpleName, `qualifier_type' is null.
2884 // The `qualifier_type' is used for the CS1540 check; it's normally either null or
2885 // the same than `queried_type' - except when we're being called from BaseAccess;
2886 // in this case, `invocation_type' is the current type and `queried_type' the base
2887 // type, so this'd normally trigger a CS1540.
2889 // The binding flags are `bf' and the kind of members being looked up are `mt'
2891 // The return value always includes private members which code in `invocation_type'
2892 // is allowed to access (using the specified `qualifier_type' if given); only use
2893 // BindingFlags.NonPublic to bypass the permission check.
2895 // The 'almost_match' argument is used for reporting error CS1540.
2897 // Returns an array of a single element for everything but Methods/Constructors
2898 // that might return multiple matches.
2900 public static MemberInfo [] MemberLookup (Type invocation_type, Type qualifier_type,
2901 Type queried_type, MemberTypes mt,
2902 BindingFlags original_bf, string name, IList almost_match)
2904 Timer.StartTimer (TimerType.MemberLookup);
2906 MemberInfo[] retval = RealMemberLookup (invocation_type, qualifier_type,
2907 queried_type, mt, original_bf, name, almost_match);
2909 Timer.StopTimer (TimerType.MemberLookup);
2914 static MemberInfo [] RealMemberLookup (Type invocation_type, Type qualifier_type,
2915 Type queried_type, MemberTypes mt,
2916 BindingFlags original_bf, string name, IList almost_match)
2918 BindingFlags bf = original_bf;
2920 ArrayList method_list = null;
2921 Type current_type = queried_type;
2922 bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0;
2923 bool skip_iface_check = true, used_cache = false;
2924 bool always_ok_flag = false;
2926 closure.invocation_type = invocation_type;
2927 closure.invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
2928 closure.qualifier_type = qualifier_type;
2929 closure.almost_match = almost_match;
2932 // If we are a nested class, we always have access to our container
2935 if (invocation_type != null){
2936 string invocation_name = invocation_type.FullName;
2937 if ((invocation_name != null) && (invocation_name.IndexOf ('+') != -1)){
2938 string container = queried_type.FullName + "+";
2939 int container_length = container.Length;
2941 if (invocation_name.Length > container_length){
2942 string shared = invocation_name.Substring (0, container_length);
2944 if (shared == container)
2945 always_ok_flag = true;
2950 // This is from the first time we find a method
2951 // in most cases, we do not actually find a method in the base class
2952 // so we can just ignore it, and save the arraylist allocation
2953 MemberInfo [] first_members_list = null;
2954 bool use_first_members_list = false;
2960 // `NonPublic' is lame, because it includes both protected and
2961 // private methods, so we need to control this behavior by
2962 // explicitly tracking if a private method is ok or not.
2964 // The possible cases are:
2965 // public, private and protected (internal does not come into the
2968 if ((invocation_type != null) &&
2969 ((invocation_type == current_type) ||
2970 IsNestedChildOf (invocation_type, current_type)) ||
2972 bf = original_bf | BindingFlags.NonPublic;
2976 closure.private_ok = (original_bf & BindingFlags.NonPublic) != 0;
2978 Timer.StopTimer (TimerType.MemberLookup);
2980 list = MemberLookup_FindMembers (
2981 current_type, mt, bf, name, out used_cache);
2983 Timer.StartTimer (TimerType.MemberLookup);
2986 // When queried for an interface type, the cache will automatically check all
2987 // inherited members, so we don't need to do this here. However, this only
2988 // works if we already used the cache in the first iteration of this loop.
2990 // If we used the cache in any further iteration, we can still terminate the
2991 // loop since the cache always looks in all parent classes.
2997 skip_iface_check = false;
2999 if (current_type == TypeManager.object_type)
3002 current_type = current_type.BaseType;
3005 // This happens with interfaces, they have a null
3006 // basetype. Look members up in the Object class.
3008 if (current_type == null)
3009 current_type = TypeManager.object_type;
3012 if (list.Length == 0)
3016 // Events and types are returned by both `static' and `instance'
3017 // searches, which means that our above FindMembers will
3018 // return two copies of the same.
3020 if (list.Length == 1 && !(list [0] is MethodBase)){
3025 // Multiple properties: we query those just to find out the indexer
3028 if (list [0] is PropertyInfo)
3032 // We found an event: the cache lookup returns both the event and
3033 // its private field.
3035 if (list [0] is EventInfo) {
3036 if ((list.Length == 2) && (list [1] is FieldInfo))
3037 return new MemberInfo [] { list [0] };
3044 // We found methods, turn the search into "method scan"
3048 if (first_members_list != null) {
3049 if (use_first_members_list) {
3050 method_list = CopyNewMethods (method_list, first_members_list);
3051 use_first_members_list = false;
3054 method_list = CopyNewMethods (method_list, list);
3056 first_members_list = list;
3057 use_first_members_list = true;
3059 mt &= (MemberTypes.Method | MemberTypes.Constructor);
3061 } while (searching);
3063 if (use_first_members_list) {
3064 foreach (MemberInfo mi in first_members_list) {
3065 if (! (mi is MethodBase)) {
3066 method_list = CopyNewMethods (method_list, first_members_list);
3067 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
3070 return (MemberInfo []) first_members_list;
3073 if (method_list != null && method_list.Count > 0) {
3074 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
3077 // This happens if we already used the cache in the first iteration, in this case
3078 // the cache already looked in all interfaces.
3080 if (skip_iface_check)
3084 // Interfaces do not list members they inherit, so we have to
3087 if (!queried_type.IsInterface)
3090 if (queried_type.IsArray)
3091 queried_type = TypeManager.array_type;
3093 TypeExpr [] ifaces = GetInterfaces (queried_type);
3097 foreach (TypeExpr itype in ifaces){
3100 x = MemberLookup (null, null, itype.Type, mt, bf, name, null);
3109 // This is used to extract properties and event declarations from a type
3111 static MemberInfo [] SpecialContainerLookup (Type t, bool is_static)
3113 BindingFlags bf = BindingFlags.DeclaredOnly | (is_static ? BindingFlags.Static : BindingFlags.Instance);
3115 bf |= BindingFlags.Public | BindingFlags.NonPublic;
3117 if (t is TypeBuilder) {
3118 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
3120 return (MemberInfo []) decl.FindMembers (
3121 MemberTypes.Property | MemberTypes.Event,
3122 bf, FilterNone_delegate, null);
3124 return t.FindMembers (MemberTypes.Property | MemberTypes.Event,
3125 bf, FilterNone_delegate, null);
3130 public static bool IsSpecialMethod (MethodBase mb)
3132 Type t = mb.DeclaringType;
3134 MemberInfo [] matches = TypeManager.SpecialContainerLookup (t, mb.IsStatic);
3135 if (matches == null)
3138 foreach (MemberInfo mi in matches){
3139 if (mi is PropertyBuilder){
3140 Pair p = (Pair) properties [mi];
3142 if (p.First == mb || p.Second == mb)
3144 } else if (mi is PropertyInfo){
3145 MethodInfo [] methods = ((PropertyInfo) mi).GetAccessors (true);
3147 foreach (MethodInfo m in methods){
3151 } else if (mi is MyEventBuilder){
3152 Pair p = (Pair) events [mi];
3154 if (p.First == mb || p.Second == mb)
3156 } else if (mi is EventInfo){
3157 EventInfo ei = ((EventInfo) mi);
3159 if (ei.GetAddMethod (true) == mb)
3162 if (ei.GetRemoveMethod (true) == mb)
3165 if (ei.GetRaiseMethod (true) == mb)
3171 // Now check if it is an operator method
3175 if (s.StartsWith ("op_")){
3176 foreach (string name in Unary.oper_names){
3181 foreach (string name in Binary.oper_names){
3195 /// There is exactly one instance of this class per type.
3197 public sealed class TypeHandle : IMemberContainer {
3198 public readonly TypeHandle BaseType;
3200 readonly int id = ++next_id;
3201 static int next_id = 0;
3204 /// Lookup a TypeHandle instance for the given type. If the type doesn't have
3205 /// a TypeHandle yet, a new instance of it is created. This static method
3206 /// ensures that we'll only have one TypeHandle instance per type.
3208 public static TypeHandle GetTypeHandle (Type t)
3210 TypeHandle handle = (TypeHandle) type_hash [t];
3214 handle = new TypeHandle (t);
3215 type_hash.Add (t, handle);
3219 public static void CleanUp ()
3225 /// Returns the TypeHandle for TypeManager.object_type.
3227 public static IMemberContainer ObjectType {
3229 if (object_type != null)
3232 object_type = GetTypeHandle (TypeManager.object_type);
3239 /// Returns the TypeHandle for TypeManager.array_type.
3241 public static IMemberContainer ArrayType {
3243 if (array_type != null)
3246 array_type = GetTypeHandle (TypeManager.array_type);
3252 private static PtrHashtable type_hash = new PtrHashtable ();
3254 private static TypeHandle object_type = null;
3255 private static TypeHandle array_type = null;
3258 private string full_name;
3259 private bool is_interface;
3260 private MemberCache member_cache;
3262 private TypeHandle (Type type)
3265 full_name = type.FullName != null ? type.FullName : type.Name;
3266 if (type.BaseType != null)
3267 BaseType = GetTypeHandle (type.BaseType);
3268 this.is_interface = type.IsInterface || type.IsGenericParameter;
3269 this.member_cache = new MemberCache (this);
3272 // IMemberContainer methods
3274 public string Name {
3286 public IMemberContainer Parent {
3292 public bool IsInterface {
3294 return is_interface;
3298 public MemberList GetMembers (MemberTypes mt, BindingFlags bf)
3300 MemberInfo [] members;
3301 if (type is GenericTypeParameterBuilder)
3302 return MemberList.Empty;
3303 if (mt == MemberTypes.Event)
3304 members = type.GetEvents (bf | BindingFlags.DeclaredOnly);
3306 members = type.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
3308 Array.Reverse (members);
3310 return new MemberList (members);
3313 // IMemberFinder methods
3315 public MemberList FindMembers (MemberTypes mt, BindingFlags bf, string name,
3316 MemberFilter filter, object criteria)
3318 return new MemberList (member_cache.FindMembers (mt, bf, name, filter, criteria));
3321 public MemberCache MemberCache {
3323 return member_cache;
3327 public override string ToString ()
3329 if (BaseType != null)
3330 return "TypeHandle (" + id + "," + Name + " : " + BaseType + ")";
3332 return "TypeHandle (" + id + "," + Name + ")";