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;
126 // This is only used when compiling corlib
128 static public Type system_int32_type;
129 static public Type system_array_type;
130 static public Type system_type_type;
131 static public Type system_assemblybuilder_type;
132 static public MethodInfo system_int_array_get_length;
133 static public MethodInfo system_int_array_get_rank;
134 static public MethodInfo system_object_array_clone;
135 static public MethodInfo system_int_array_get_length_int;
136 static public MethodInfo system_int_array_get_lower_bound_int;
137 static public MethodInfo system_int_array_get_upper_bound_int;
138 static public MethodInfo system_void_array_copyto_array_int;
142 // Internal, not really used outside
144 static Type runtime_helpers_type;
147 // These methods are called by code generated by the compiler
149 static public MethodInfo string_concat_string_string;
150 static public MethodInfo string_concat_string_string_string;
151 static public MethodInfo string_concat_string_string_string_string;
152 static public MethodInfo string_concat_string_dot_dot_dot;
153 static public MethodInfo string_concat_object_object;
154 static public MethodInfo string_concat_object_object_object;
155 static public MethodInfo string_concat_object_dot_dot_dot;
156 static public MethodInfo string_isinterneted_string;
157 static public MethodInfo system_type_get_type_from_handle;
158 static public MethodInfo object_getcurrent_void;
159 static public MethodInfo bool_movenext_void;
160 static public MethodInfo ienumerable_getenumerator_void;
161 static public MethodInfo void_reset_void;
162 static public MethodInfo void_dispose_void;
163 static public MethodInfo void_monitor_enter_object;
164 static public MethodInfo void_monitor_exit_object;
165 static public MethodInfo void_initializearray_array_fieldhandle;
166 static public MethodInfo int_getlength_int;
167 static public MethodInfo delegate_combine_delegate_delegate;
168 static public MethodInfo delegate_remove_delegate_delegate;
169 static public MethodInfo int_get_offset_to_string_data;
170 static public MethodInfo int_array_get_length;
171 static public MethodInfo int_array_get_rank;
172 static public MethodInfo object_array_clone;
173 static public MethodInfo int_array_get_length_int;
174 static public MethodInfo int_array_get_lower_bound_int;
175 static public MethodInfo int_array_get_upper_bound_int;
176 static public MethodInfo void_array_copyto_array_int;
177 static public MethodInfo activator_create_instance;
180 // The attribute constructors.
182 static public ConstructorInfo object_ctor;
183 static public ConstructorInfo cons_param_array_attribute;
184 static public ConstructorInfo void_decimal_ctor_five_args;
185 static public ConstructorInfo unverifiable_code_ctor;
186 static public ConstructorInfo invalid_operation_ctor;
189 // Holds the Array of Assemblies that have been loaded
190 // (either because it is the default or the user used the
191 // -r command line option)
193 static Assembly [] assemblies;
196 // Keeps a list of modules. We used this to do lookups
197 // on the module using GetType -- needed for arrays
199 static Module [] modules;
202 // This is the type_cache from the assemblies to avoid
203 // hitting System.Reflection on every lookup.
205 static Hashtable types;
208 // This is used to hotld the corresponding TypeContainer objects
209 // since we need this in FindMembers
211 static Hashtable typecontainers;
214 // Keeps track of those types that are defined by the
217 static ArrayList user_types;
219 static PtrHashtable builder_to_declspace;
222 // Tracks the interfaces implemented by typebuilders. We only
223 // enter those who do implement or or more interfaces
225 static PtrHashtable builder_to_ifaces;
228 // Tracks the generic parameters.
230 static PtrHashtable builder_to_type_param;
233 // Maps MethodBase.RuntimeTypeHandle to a Type array that contains
234 // the arguments to the method
236 static Hashtable method_arguments;
239 // Maps PropertyBuilder to a Type array that contains
240 // the arguments to the indexer
242 static Hashtable indexer_arguments;
245 // Maybe `method_arguments' should be replaced and only
246 // method_internal_params should be kept?
248 static Hashtable method_internal_params;
251 // Keeps track of methods
254 static Hashtable builder_to_method;
257 // Contains all public types from referenced assemblies.
258 // This member is used only if CLS Compliance verification is required.
260 public static Hashtable all_imported_types;
267 public static void CleanUp ()
269 // Lets get everything clean so that we can collect before generating code
273 typecontainers = null;
275 builder_to_declspace = null;
276 builder_to_ifaces = null;
277 method_arguments = null;
278 indexer_arguments = null;
279 method_internal_params = null;
280 builder_to_method = null;
281 builder_to_type_param = null;
285 negative_hits = null;
286 builder_to_constant = null;
287 fieldbuilders_to_fields = null;
289 priv_fields_events = null;
292 TypeHandle.CleanUp ();
296 /// A filter for Findmembers that uses the Signature object to
299 static bool SignatureFilter (MemberInfo mi, object criteria)
301 Signature sig = (Signature) criteria;
303 if (!(mi is MethodBase))
306 if (mi.Name != sig.name)
309 int count = sig.args.Length;
311 if (mi is MethodBuilder || mi is ConstructorBuilder){
312 Type [] candidate_args = GetArgumentTypes ((MethodBase) mi);
314 if (candidate_args.Length != count)
317 for (int i = 0; i < count; i++)
318 if (candidate_args [i] != sig.args [i])
323 ParameterInfo [] pars = ((MethodBase) mi).GetParameters ();
325 if (pars.Length != count)
328 for (int i = 0; i < count; i++)
329 if (pars [i].ParameterType != sig.args [i])
335 // A delegate that points to the filter above.
336 static MemberFilter signature_filter;
339 // These are expressions that represent some of the internal data types, used
342 static void InitExpressionTypes ()
344 system_object_expr = new TypeLookupExpression ("System.Object");
345 system_string_expr = new TypeLookupExpression ("System.String");
346 system_boolean_expr = new TypeLookupExpression ("System.Boolean");
347 system_decimal_expr = new TypeLookupExpression ("System.Decimal");
348 system_single_expr = new TypeLookupExpression ("System.Single");
349 system_double_expr = new TypeLookupExpression ("System.Double");
350 system_sbyte_expr = new TypeLookupExpression ("System.SByte");
351 system_byte_expr = new TypeLookupExpression ("System.Byte");
352 system_int16_expr = new TypeLookupExpression ("System.Int16");
353 system_uint16_expr = new TypeLookupExpression ("System.UInt16");
354 system_int32_expr = new TypeLookupExpression ("System.Int32");
355 system_uint32_expr = new TypeLookupExpression ("System.UInt32");
356 system_int64_expr = new TypeLookupExpression ("System.Int64");
357 system_uint64_expr = new TypeLookupExpression ("System.UInt64");
358 system_char_expr = new TypeLookupExpression ("System.Char");
359 system_void_expr = new TypeLookupExpression ("System.Void");
360 system_asynccallback_expr = new TypeLookupExpression ("System.AsyncCallback");
361 system_iasyncresult_expr = new TypeLookupExpression ("System.IAsyncResult");
362 system_valuetype_expr = new TypeLookupExpression ("System.ValueType");
365 static TypeManager ()
367 assemblies = new Assembly [0];
369 user_types = new ArrayList ();
371 types = new Hashtable ();
372 typecontainers = new Hashtable ();
374 builder_to_declspace = new PtrHashtable ();
375 builder_to_method = new PtrHashtable ();
376 method_arguments = new PtrHashtable ();
377 method_internal_params = new PtrHashtable ();
378 indexer_arguments = new PtrHashtable ();
379 builder_to_ifaces = new PtrHashtable ();
380 builder_to_type_param = new PtrHashtable ();
382 NoTypes = new Type [0];
383 NoTypeExprs = new TypeExpr [0];
385 signature_filter = new MemberFilter (SignatureFilter);
386 InitExpressionTypes ();
389 public static void HandleDuplicate (string name, Type t)
391 Type prev = (Type) types [name];
392 TypeContainer tc = builder_to_declspace [prev] as TypeContainer;
396 // This probably never happens, as we catch this before
398 Report.Error (-17, "The type `" + name + "' has already been defined.");
402 tc = builder_to_declspace [t] as TypeContainer;
405 1595, "The type `" + name + "' is defined in an existing assembly;"+
406 " Using the new definition from: " + tc.Location);
409 1595, "The type `" + name + "' is defined in an existing assembly;");
412 Report.Warning (1595, "Previously defined in: " + prev.Assembly.FullName);
418 public static void AddUserType (string name, TypeBuilder t)
423 HandleDuplicate (name, t);
429 // This entry point is used by types that we define under the covers
431 public static void RegisterBuilder (Type tb, Type [] ifaces)
434 builder_to_ifaces [tb] = ifaces;
437 public static void AddUserType (string name, TypeBuilder t, TypeContainer tc)
439 builder_to_declspace.Add (t, tc);
440 typecontainers.Add (name, tc);
441 AddUserType (name, t);
444 public static void AddDelegateType (string name, TypeBuilder t, Delegate del)
449 HandleDuplicate (name, t);
452 builder_to_declspace.Add (t, del);
455 public static void AddEnumType (string name, TypeBuilder t, Enum en)
460 HandleDuplicate (name, t);
462 builder_to_declspace.Add (t, en);
465 public static void AddMethod (MethodBase builder, IMethodData method)
467 builder_to_method.Add (builder, method);
470 public static IMethodData GetMethod (MethodBase builder)
472 return (IMethodData) builder_to_method [builder];
475 public static void AddTypeParameter (Type t, TypeParameter tparam)
477 if (!builder_to_type_param.Contains (t))
478 builder_to_type_param.Add (t, tparam);
482 /// Returns the DeclSpace whose Type is `t' or null if there is no
483 /// DeclSpace for `t' (ie, the Type comes from a library)
485 public static DeclSpace LookupDeclSpace (Type t)
487 return builder_to_declspace [t] as DeclSpace;
491 /// Returns the TypeContainer whose Type is `t' or null if there is no
492 /// TypeContainer for `t' (ie, the Type comes from a library)
494 public static TypeContainer LookupTypeContainer (Type t)
496 return builder_to_declspace [t] as TypeContainer;
499 public static IMemberContainer LookupMemberContainer (Type t)
501 if (t is TypeBuilder) {
502 IMemberContainer container = builder_to_declspace [t] as IMemberContainer;
503 if (container != null)
507 if (t is GenericTypeParameterBuilder) {
508 IMemberContainer container = builder_to_type_param [t] as IMemberContainer;
510 if (container != null)
514 return TypeHandle.GetTypeHandle (t);
517 public static TypeContainer LookupInterface (Type t)
519 TypeContainer tc = (TypeContainer) builder_to_declspace [t];
520 if ((tc == null) || (tc.Kind != Kind.Interface))
526 public static Delegate LookupDelegate (Type t)
528 return builder_to_declspace [t] as Delegate;
531 public static Enum LookupEnum (Type t)
533 return builder_to_declspace [t] as Enum;
536 public static Class LookupClass (Type t)
538 return (Class) builder_to_declspace [t];
541 public static TypeParameter LookupTypeParameter (Type t)
543 return (TypeParameter) builder_to_type_param [t];
546 public static bool HasConstructorConstraint (Type t)
548 if (!t.IsGenericParameter)
549 throw new InvalidOperationException ();
551 TypeParameter tparam = LookupTypeParameter (t);
553 return tparam.HasConstructorConstraint;
555 object[] attrs = t.GetCustomAttributes (
556 TypeManager.new_constraint_attr_type, false);
558 return attrs.Length > 0;
563 /// Registers an assembly to load types from.
565 public static void AddAssembly (Assembly a)
567 foreach (Assembly assembly in assemblies) {
572 int top = assemblies.Length;
573 Assembly [] n = new Assembly [top + 1];
575 assemblies.CopyTo (n, 0);
581 public static Assembly [] GetAssemblies ()
587 /// Registers a module builder to lookup types from
589 public static void AddModule (Module mb)
591 int top = modules != null ? modules.Length : 0;
592 Module [] n = new Module [top + 1];
595 modules.CopyTo (n, 0);
600 public static Module[] Modules {
606 static Hashtable references = new Hashtable ();
609 // Gets the reference to T version of the Type (T&)
611 public static Type GetReferenceType (Type t)
613 return t.MakeByRefType ();
616 static Hashtable pointers = new Hashtable ();
619 // Gets the pointer to T version of the Type (T*)
621 public static Type GetPointerType (Type t)
623 string tname = t.FullName + "*";
625 Type ret = t.Assembly.GetType (tname);
628 // If the type comes from the assembly we are building
629 // We need the Hashtable, because .NET 1.1 will return different instance types
630 // every time we call ModuleBuilder.GetType.
633 if (pointers [t] == null)
634 pointers [t] = CodeGen.Module.Builder.GetType (tname);
636 ret = (Type) pointers [t];
643 // Low-level lookup, cache-less
645 static Type LookupTypeReflection (string name)
649 foreach (Assembly a in assemblies){
650 t = a.GetType (name);
655 TypeAttributes ta = t.Attributes & TypeAttributes.VisibilityMask;
656 if (ta == TypeAttributes.NotPublic ||
657 ta == TypeAttributes.NestedPrivate ||
658 ta == TypeAttributes.NestedAssembly ||
659 ta == TypeAttributes.NestedFamANDAssem){
662 // In .NET pointers turn out to be private, even if their
663 // element type is not
666 t = t.GetElementType ();
676 foreach (Module mb in modules) {
677 t = mb.GetType (name);
685 static Hashtable negative_hits = new Hashtable ();
688 // This function is used when you want to avoid the lookups, and want to go
689 // directly to the source. This will use the cache.
691 // Notice that bypassing the cache is bad, because on Microsoft.NET runtime
692 // GetType ("DynamicType[]") != GetType ("DynamicType[]"), and there is no
693 // way to test things other than doing a fullname compare
695 public static Type LookupTypeDirect (string name)
697 Type t = (Type) types [name];
701 t = LookupTypeReflection (name);
709 static readonly char [] dot_array = { '.' };
712 /// Returns the Type associated with @name, takes care of the fact that
713 /// reflection expects nested types to be separated from the main type
714 /// with a "+" instead of a "."
716 public static Type LookupType (string name)
721 // First lookup in user defined and cached values
724 t = (Type) types [name];
728 // Two thirds of the failures are caught here.
729 if (negative_hits.Contains (name))
732 // Sadly, split takes a param array, so this ends up allocating *EVERY TIME*
733 string [] elements = name.Split (dot_array);
734 int count = elements.Length;
736 for (int n = 1; n <= count; n++){
737 string top_level_type = String.Join (".", elements, 0, n);
739 // One third of the failures are caught here.
740 if (negative_hits.Contains (top_level_type))
743 t = (Type) types [top_level_type];
745 t = LookupTypeReflection (top_level_type);
747 negative_hits [top_level_type] = null;
758 // We know that System.Object does not have children, and since its the parent of
759 // all the objects, it always gets probbed for inner classes.
761 if (top_level_type == "System.Object")
764 string newt = top_level_type + "+" + String.Join ("+", elements, n, count - n);
765 //Console.WriteLine ("Looking up: " + newt + " " + name);
766 t = LookupTypeReflection (newt);
768 negative_hits [name] = null;
773 negative_hits [name] = null;
778 /// Computes the namespaces that we import from the assemblies we reference.
780 public static void ComputeNamespaces ()
782 MethodInfo assembly_get_namespaces = typeof (Assembly).GetMethod ("GetNamespaces", BindingFlags.Instance|BindingFlags.NonPublic);
785 // First add the assembly namespaces
787 if (assembly_get_namespaces != null){
788 int count = assemblies.Length;
790 for (int i = 0; i < count; i++){
791 Assembly a = assemblies [i];
792 string [] namespaces = (string []) assembly_get_namespaces.Invoke (a, null);
793 foreach (string ns in namespaces){
796 Namespace.LookupNamespace (ns, true);
800 Hashtable cache = new Hashtable ();
801 cache.Add ("", null);
802 foreach (Assembly a in assemblies) {
803 foreach (Type t in a.GetExportedTypes ()) {
804 string ns = t.Namespace;
805 if (ns == null || cache.Contains (ns))
808 Namespace.LookupNamespace (ns, true);
809 cache.Add (ns, null);
816 /// Fills static table with exported types from all referenced assemblies.
817 /// This information is required for CLS Compliance tests.
819 public static void LoadAllImportedTypes ()
821 if (!CodeGen.Assembly.IsClsCompliant)
824 all_imported_types = new Hashtable ();
825 foreach (Assembly a in assemblies) {
826 foreach (Type t in a.GetExportedTypes ()) {
827 all_imported_types [t.FullName] = t;
832 public static bool NamespaceClash (string name, Location loc)
834 if (Namespace.LookupNamespace (name, false) == null)
837 Report.Error (519, loc, String.Format ("`{0}' clashes with a predefined namespace", name));
842 /// Returns the C# name of a type if possible, or the full type name otherwise
844 static public string CSharpName (Type t)
846 if (t.FullName == null)
849 return Regex.Replace (t.FullName,
851 @"(Int32|UInt32|Int16|UInt16|Int64|UInt64|" +
852 @"Single|Double|Char|Decimal|Byte|SByte|Object|" +
853 @"Boolean|String|Void)" +
855 new MatchEvaluator (CSharpNameMatch));
858 static String CSharpNameMatch (Match match)
860 string s = match.Groups [1].Captures [0].Value;
862 Replace ("int32", "int").
863 Replace ("uint32", "uint").
864 Replace ("int16", "short").
865 Replace ("uint16", "ushort").
866 Replace ("int64", "long").
867 Replace ("uint64", "ulong").
868 Replace ("single", "float").
869 Replace ("boolean", "bool")
870 + match.Groups [2].Captures [0].Value;
874 /// Returns the signature of the method with full namespace classification
876 static public string GetFullNameSignature (MemberInfo mi)
878 return mi.DeclaringType.FullName.Replace ('+', '.') + '.' + mi.Name;
881 static public string GetFullNameSignature (MethodBase mb)
883 string name = mb.Name;
885 name = mb.DeclaringType.Name;
887 if (mb.IsSpecialName) {
888 if (name.StartsWith ("get_") || name.StartsWith ("set_")) {
889 name = name.Remove (0, 4);
896 return mb.DeclaringType.FullName.Replace ('+', '.') + '.' + name;
899 static public string GetFullName (Type t)
901 if (t.FullName == null)
904 string name = t.FullName.Replace ('+', '.');
906 DeclSpace tc = LookupDeclSpace (t);
907 if ((tc != null) && tc.IsGeneric) {
908 TypeParameter[] tparam = tc.TypeParameters;
910 StringBuilder sb = new StringBuilder (name);
912 for (int i = 0; i < tparam.Length; i++) {
915 sb.Append (tparam [i].Name);
918 return sb.ToString ();
919 } else if (t.HasGenericArguments && !t.IsGenericInstance) {
920 Type[] tparam = t.GetGenericArguments ();
922 StringBuilder sb = new StringBuilder (name);
924 for (int i = 0; i < tparam.Length; i++) {
927 sb.Append (tparam [i].Name);
930 return sb.ToString ();
937 /// Returns the signature of the property and indexer
939 static public string CSharpSignature (PropertyBuilder pb, bool is_indexer)
942 return GetFullNameSignature (pb);
945 MethodBase mb = pb.GetSetMethod (true) != null ? pb.GetSetMethod (true) : pb.GetGetMethod (true);
946 string signature = GetFullNameSignature (mb);
947 string arg = TypeManager.LookupParametersByBuilder (mb).ParameterDesc (0);
948 return String.Format ("{0}.this[{1}]", signature.Substring (0, signature.LastIndexOf ('.')), arg);
952 /// Returns the signature of the method
954 static public string CSharpSignature (MethodBase mb)
956 StringBuilder sig = new StringBuilder ("(");
959 // FIXME: We should really have a single function to do
960 // everything instead of the following 5 line pattern
962 ParameterData iparams = LookupParametersByBuilder (mb);
965 iparams = new ReflectionParameters (mb);
968 if (mb.IsSpecialName && iparams.Count == 0)
969 return GetFullNameSignature (mb);
971 for (int i = 0; i < iparams.Count; i++) {
975 sig.Append (iparams.ParameterDesc (i));
980 if (mb.IsSpecialName && iparams.Count == 1) {
981 sig.Replace ('(', '[');
982 sig.Replace (')', ']');
985 return GetFullNameSignature (mb) + sig.ToString ();
989 /// Looks up a type, and aborts if it is not found. This is used
990 /// by types required by the compiler
992 static Type CoreLookupType (string name)
994 Type t = LookupTypeDirect (name);
997 Report.Error (518, "The predefined type `" + name + "' is not defined or imported");
998 Environment.Exit (1);
1005 /// Returns the MethodInfo for a method named `name' defined
1006 /// in type `t' which takes arguments of types `args'
1008 static MethodInfo GetMethod (Type t, string name, Type [] args, bool is_private, bool report_errors)
1012 BindingFlags flags = instance_and_static | BindingFlags.Public;
1018 flags |= BindingFlags.NonPublic;
1020 list = FindMembers (t, MemberTypes.Method, flags, signature_filter, sig);
1021 if (list.Count == 0) {
1023 Report.Error (-19, "Can not find the core function `" + name + "'");
1027 MethodInfo mi = list [0] as MethodInfo;
1030 Report.Error (-19, "Can not find the core function `" + name + "'");
1037 static MethodInfo GetMethod (Type t, string name, Type [] args, bool report_errors)
1039 return GetMethod (t, name, args, false, report_errors);
1042 static MethodInfo GetMethod (Type t, string name, Type [] args)
1044 return GetMethod (t, name, args, true);
1049 /// Returns the ConstructorInfo for "args"
1051 static ConstructorInfo GetConstructor (Type t, Type [] args)
1059 list = FindMembers (t, MemberTypes.Constructor,
1060 instance_and_static | BindingFlags.Public | BindingFlags.DeclaredOnly,
1061 signature_filter, sig);
1062 if (list.Count == 0){
1063 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
1067 ConstructorInfo ci = list [0] as ConstructorInfo;
1069 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
1076 public static void InitEnumUnderlyingTypes ()
1079 int32_type = CoreLookupType ("System.Int32");
1080 int64_type = CoreLookupType ("System.Int64");
1081 uint32_type = CoreLookupType ("System.UInt32");
1082 uint64_type = CoreLookupType ("System.UInt64");
1083 byte_type = CoreLookupType ("System.Byte");
1084 sbyte_type = CoreLookupType ("System.SByte");
1085 short_type = CoreLookupType ("System.Int16");
1086 ushort_type = CoreLookupType ("System.UInt16");
1090 /// The types have to be initialized after the initial
1091 /// population of the type has happened (for example, to
1092 /// bootstrap the corlib.dll
1094 public static void InitCoreTypes ()
1096 object_type = CoreLookupType ("System.Object");
1097 value_type = CoreLookupType ("System.ValueType");
1099 InitEnumUnderlyingTypes ();
1101 char_type = CoreLookupType ("System.Char");
1102 string_type = CoreLookupType ("System.String");
1103 float_type = CoreLookupType ("System.Single");
1104 double_type = CoreLookupType ("System.Double");
1105 char_ptr_type = CoreLookupType ("System.Char*");
1106 decimal_type = CoreLookupType ("System.Decimal");
1107 bool_type = CoreLookupType ("System.Boolean");
1108 enum_type = CoreLookupType ("System.Enum");
1110 multicast_delegate_type = CoreLookupType ("System.MulticastDelegate");
1111 delegate_type = CoreLookupType ("System.Delegate");
1113 array_type = CoreLookupType ("System.Array");
1114 void_type = CoreLookupType ("System.Void");
1115 type_type = CoreLookupType ("System.Type");
1117 runtime_field_handle_type = CoreLookupType ("System.RuntimeFieldHandle");
1118 runtime_argument_handle_type = CoreLookupType ("System.RuntimeArgumentHandle");
1119 runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices.RuntimeHelpers");
1120 default_member_type = CoreLookupType ("System.Reflection.DefaultMemberAttribute");
1121 runtime_handle_type = CoreLookupType ("System.RuntimeTypeHandle");
1122 asynccallback_type = CoreLookupType ("System.AsyncCallback");
1123 iasyncresult_type = CoreLookupType ("System.IAsyncResult");
1124 ienumerator_type = CoreLookupType ("System.Collections.IEnumerator");
1125 ienumerable_type = CoreLookupType ("System.Collections.IEnumerable");
1126 idisposable_type = CoreLookupType ("System.IDisposable");
1127 icloneable_type = CoreLookupType ("System.ICloneable");
1128 iconvertible_type = CoreLookupType ("System.IConvertible");
1129 monitor_type = CoreLookupType ("System.Threading.Monitor");
1130 intptr_type = CoreLookupType ("System.IntPtr");
1132 attribute_type = CoreLookupType ("System.Attribute");
1133 attribute_usage_type = CoreLookupType ("System.AttributeUsageAttribute");
1134 dllimport_type = CoreLookupType ("System.Runtime.InteropServices.DllImportAttribute");
1135 methodimpl_attr_type = CoreLookupType ("System.Runtime.CompilerServices.MethodImplAttribute");
1136 marshal_as_attr_type = CoreLookupType ("System.Runtime.InteropServices.MarshalAsAttribute");
1137 new_constraint_attr_type = CoreLookupType ("System.Runtime.CompilerServices.NewConstraintAttribute");
1138 param_array_type = CoreLookupType ("System.ParamArrayAttribute");
1139 in_attribute_type = CoreLookupType ("System.Runtime.InteropServices.InAttribute");
1140 typed_reference_type = CoreLookupType ("System.TypedReference");
1141 arg_iterator_type = CoreLookupType ("System.ArgIterator");
1142 mbr_type = CoreLookupType ("System.MarshalByRefObject");
1145 // Sigh. Remove this before the release. Wonder what versions of Mono
1146 // people are running.
1148 guid_attr_type = LookupType ("System.Runtime.InteropServices.GuidAttribute");
1150 unverifiable_code_type= CoreLookupType ("System.Security.UnverifiableCodeAttribute");
1152 void_ptr_type = CoreLookupType ("System.Void*");
1154 indexer_name_type = CoreLookupType ("System.Runtime.CompilerServices.IndexerNameAttribute");
1156 exception_type = CoreLookupType ("System.Exception");
1157 activator_type = CoreLookupType ("System.Activator");
1158 invalid_operation_exception_type = CoreLookupType ("System.InvalidOperationException");
1159 not_supported_exception_type = CoreLookupType ("System.NotSupportedException");
1164 obsolete_attribute_type = CoreLookupType ("System.ObsoleteAttribute");
1165 conditional_attribute_type = CoreLookupType ("System.Diagnostics.ConditionalAttribute");
1166 cls_compliant_attribute_type = CoreLookupType ("System.CLSCompliantAttribute");
1167 struct_layout_attribute_type = CoreLookupType ("System.Runtime.InteropServices.StructLayoutAttribute");
1168 field_offset_attribute_type = CoreLookupType ("System.Runtime.InteropServices.FieldOffsetAttribute");
1173 generic_ienumerator_type = CoreLookupType (MemberName.MakeName ("System.Collections.Generic.IEnumerator", 1));
1174 generic_ienumerable_type = CoreLookupType (MemberName.MakeName ("System.Collections.Generic.IEnumerable", 1));
1178 // When compiling corlib, store the "real" types here.
1180 if (!RootContext.StdLib) {
1181 system_int32_type = typeof (System.Int32);
1182 system_array_type = typeof (System.Array);
1183 system_type_type = typeof (System.Type);
1184 system_assemblybuilder_type = typeof (System.Reflection.Emit.AssemblyBuilder);
1186 Type [] void_arg = { };
1187 system_int_array_get_length = GetMethod (
1188 system_array_type, "get_Length", void_arg);
1189 system_int_array_get_rank = GetMethod (
1190 system_array_type, "get_Rank", void_arg);
1191 system_object_array_clone = GetMethod (
1192 system_array_type, "Clone", void_arg);
1194 Type [] system_int_arg = { system_int32_type };
1195 system_int_array_get_length_int = GetMethod (
1196 system_array_type, "GetLength", system_int_arg);
1197 system_int_array_get_upper_bound_int = GetMethod (
1198 system_array_type, "GetUpperBound", system_int_arg);
1199 system_int_array_get_lower_bound_int = GetMethod (
1200 system_array_type, "GetLowerBound", system_int_arg);
1202 Type [] system_array_int_arg = { system_array_type, system_int32_type };
1203 system_void_array_copyto_array_int = GetMethod (
1204 system_array_type, "CopyTo", system_array_int_arg);
1206 Type [] system_3_type_arg = {
1207 system_type_type, system_type_type, system_type_type };
1208 Type [] system_4_type_arg = {
1209 system_type_type, system_type_type, system_type_type, system_type_type };
1211 MethodInfo set_corlib_type_builders = GetMethod (
1212 system_assemblybuilder_type, "SetCorlibTypeBuilders",
1213 system_4_type_arg, true, false);
1215 if (set_corlib_type_builders != null) {
1216 object[] args = new object [4];
1217 args [0] = object_type;
1218 args [1] = value_type;
1219 args [2] = enum_type;
1220 args [3] = void_type;
1222 set_corlib_type_builders.Invoke (CodeGen.Assembly.Builder, args);
1224 // Compatibility for an older version of the class libs.
1225 set_corlib_type_builders = GetMethod (
1226 system_assemblybuilder_type, "SetCorlibTypeBuilders",
1227 system_3_type_arg, true, true);
1229 if (set_corlib_type_builders == null) {
1230 Report.Error (-26, "Corlib compilation is not supported in Microsoft.NET due to bugs in it");
1234 object[] args = new object [3];
1235 args [0] = object_type;
1236 args [1] = value_type;
1237 args [2] = enum_type;
1239 set_corlib_type_builders.Invoke (CodeGen.Assembly.Builder, args);
1243 system_object_expr.Type = object_type;
1244 system_string_expr.Type = string_type;
1245 system_boolean_expr.Type = bool_type;
1246 system_decimal_expr.Type = decimal_type;
1247 system_single_expr.Type = float_type;
1248 system_double_expr.Type = double_type;
1249 system_sbyte_expr.Type = sbyte_type;
1250 system_byte_expr.Type = byte_type;
1251 system_int16_expr.Type = short_type;
1252 system_uint16_expr.Type = ushort_type;
1253 system_int32_expr.Type = int32_type;
1254 system_uint32_expr.Type = uint32_type;
1255 system_int64_expr.Type = int64_type;
1256 system_uint64_expr.Type = uint64_type;
1257 system_char_expr.Type = char_type;
1258 system_void_expr.Type = void_type;
1259 system_asynccallback_expr.Type = asynccallback_type;
1260 system_iasyncresult_expr.Type = iasyncresult_type;
1261 system_valuetype_expr.Type = value_type;
1265 // The helper methods that are used by the compiler
1267 public static void InitCodeHelpers ()
1270 // Now load the default methods that we use.
1272 Type [] string_string = { string_type, string_type };
1273 string_concat_string_string = GetMethod (
1274 string_type, "Concat", string_string);
1275 Type [] string_string_string = { string_type, string_type, string_type };
1276 string_concat_string_string_string = GetMethod (
1277 string_type, "Concat", string_string_string);
1278 Type [] string_string_string_string = { string_type, string_type, string_type, string_type };
1279 string_concat_string_string_string_string = GetMethod (
1280 string_type, "Concat", string_string_string_string);
1281 Type[] params_string = { TypeManager.LookupType ("System.String[]") };
1282 string_concat_string_dot_dot_dot = GetMethod (
1283 string_type, "Concat", params_string);
1285 Type [] object_object = { object_type, object_type };
1286 string_concat_object_object = GetMethod (
1287 string_type, "Concat", object_object);
1288 Type [] object_object_object = { object_type, object_type, object_type };
1289 string_concat_object_object_object = GetMethod (
1290 string_type, "Concat", object_object_object);
1291 Type[] params_object = { TypeManager.LookupType ("System.Object[]") };
1292 string_concat_object_dot_dot_dot = GetMethod (
1293 string_type, "Concat", params_object);
1295 Type [] string_ = { string_type };
1296 string_isinterneted_string = GetMethod (
1297 string_type, "IsInterned", string_);
1299 Type [] runtime_type_handle = { runtime_handle_type };
1300 system_type_get_type_from_handle = GetMethod (
1301 type_type, "GetTypeFromHandle", runtime_type_handle);
1303 Type [] delegate_delegate = { delegate_type, delegate_type };
1304 delegate_combine_delegate_delegate = GetMethod (
1305 delegate_type, "Combine", delegate_delegate);
1307 delegate_remove_delegate_delegate = GetMethod (
1308 delegate_type, "Remove", delegate_delegate);
1313 Type [] void_arg = { };
1314 object_getcurrent_void = GetMethod (
1315 ienumerator_type, "get_Current", void_arg);
1316 bool_movenext_void = GetMethod (
1317 ienumerator_type, "MoveNext", void_arg);
1318 void_reset_void = GetMethod (
1319 ienumerator_type, "Reset", void_arg);
1320 void_dispose_void = GetMethod (
1321 idisposable_type, "Dispose", void_arg);
1322 int_get_offset_to_string_data = GetMethod (
1323 runtime_helpers_type, "get_OffsetToStringData", void_arg);
1324 int_array_get_length = GetMethod (
1325 array_type, "get_Length", void_arg);
1326 int_array_get_rank = GetMethod (
1327 array_type, "get_Rank", void_arg);
1328 ienumerable_getenumerator_void = GetMethod (
1329 ienumerable_type, "GetEnumerator", void_arg);
1334 Type [] int_arg = { int32_type };
1335 int_array_get_length_int = GetMethod (
1336 array_type, "GetLength", int_arg);
1337 int_array_get_upper_bound_int = GetMethod (
1338 array_type, "GetUpperBound", int_arg);
1339 int_array_get_lower_bound_int = GetMethod (
1340 array_type, "GetLowerBound", int_arg);
1343 // System.Array methods
1345 object_array_clone = GetMethod (
1346 array_type, "Clone", void_arg);
1347 Type [] array_int_arg = { array_type, int32_type };
1348 void_array_copyto_array_int = GetMethod (
1349 array_type, "CopyTo", array_int_arg);
1354 Type [] object_arg = { object_type };
1355 void_monitor_enter_object = GetMethod (
1356 monitor_type, "Enter", object_arg);
1357 void_monitor_exit_object = GetMethod (
1358 monitor_type, "Exit", object_arg);
1360 Type [] array_field_handle_arg = { array_type, runtime_field_handle_type };
1362 void_initializearray_array_fieldhandle = GetMethod (
1363 runtime_helpers_type, "InitializeArray", array_field_handle_arg);
1368 int_getlength_int = GetMethod (
1369 array_type, "GetLength", int_arg);
1372 // Decimal constructors
1374 Type [] dec_arg = { int32_type, int32_type, int32_type, bool_type, byte_type };
1375 void_decimal_ctor_five_args = GetConstructor (
1376 decimal_type, dec_arg);
1381 cons_param_array_attribute = GetConstructor (
1382 param_array_type, void_arg);
1384 unverifiable_code_ctor = GetConstructor (
1385 unverifiable_code_type, void_arg);
1388 // InvalidOperationException
1390 invalid_operation_ctor = GetConstructor (
1391 invalid_operation_exception_type, void_arg);
1395 object_ctor = GetConstructor (object_type, void_arg);
1398 Type [] type_arg = { type_type };
1399 activator_create_instance = GetMethod (
1400 activator_type, "CreateInstance", type_arg);
1403 const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance;
1406 /// This is the "old", non-cache based FindMembers() function. We cannot use
1407 /// the cache here because there is no member name argument.
1409 public static MemberList FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1410 MemberFilter filter, object criteria)
1412 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
1415 // `builder_to_declspace' contains all dynamic types.
1419 Timer.StartTimer (TimerType.FindMembers);
1420 list = decl.FindMembers (mt, bf, filter, criteria);
1421 Timer.StopTimer (TimerType.FindMembers);
1426 // We have to take care of arrays specially, because GetType on
1427 // a TypeBuilder array will return a Type, not a TypeBuilder,
1428 // and we can not call FindMembers on this type.
1430 if (t.IsSubclassOf (TypeManager.array_type))
1431 return new MemberList (TypeManager.array_type.FindMembers (mt, bf, filter, criteria));
1434 // Since FindMembers will not lookup both static and instance
1435 // members, we emulate this behaviour here.
1437 if ((bf & instance_and_static) == instance_and_static){
1438 MemberInfo [] i_members = t.FindMembers (
1439 mt, bf & ~BindingFlags.Static, filter, criteria);
1441 int i_len = i_members.Length;
1443 MemberInfo one = i_members [0];
1446 // If any of these are present, we are done!
1448 if ((one is Type) || (one is EventInfo) || (one is FieldInfo))
1449 return new MemberList (i_members);
1452 MemberInfo [] s_members = t.FindMembers (
1453 mt, bf & ~BindingFlags.Instance, filter, criteria);
1455 int s_len = s_members.Length;
1456 if (i_len > 0 || s_len > 0)
1457 return new MemberList (i_members, s_members);
1460 return new MemberList (i_members);
1462 return new MemberList (s_members);
1466 return new MemberList (t.FindMembers (mt, bf, filter, criteria));
1471 /// This method is only called from within MemberLookup. It tries to use the member
1472 /// cache if possible and falls back to the normal FindMembers if not. The `used_cache'
1473 /// flag tells the caller whether we used the cache or not. If we used the cache, then
1474 /// our return value will already contain all inherited members and the caller don't need
1475 /// to check base classes and interfaces anymore.
1477 private static MemberInfo [] MemberLookup_FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1478 string name, out bool used_cache)
1481 // We have to take care of arrays specially, because GetType on
1482 // a TypeBuilder array will return a Type, not a TypeBuilder,
1483 // and we can not call FindMembers on this type.
1485 if (t == TypeManager.array_type || t.IsSubclassOf (TypeManager.array_type)) {
1487 return TypeHandle.ArrayType.MemberCache.FindMembers (
1488 mt, bf, name, FilterWithClosure_delegate, null);
1492 // If this is a dynamic type, it's always in the `builder_to_declspace' hash table
1493 // and we can ask the DeclSpace for the MemberCache.
1495 if (t is TypeBuilder) {
1496 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
1497 MemberCache cache = decl.MemberCache;
1500 // If this DeclSpace has a MemberCache, use it.
1503 if (cache != null) {
1505 return cache.FindMembers (
1506 mt, bf, name, FilterWithClosure_delegate, null);
1509 // If there is no MemberCache, we need to use the "normal" FindMembers.
1510 // Note, this is a VERY uncommon route!
1513 Timer.StartTimer (TimerType.FindMembers);
1514 list = decl.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
1515 FilterWithClosure_delegate, name);
1516 Timer.StopTimer (TimerType.FindMembers);
1518 return (MemberInfo []) list;
1521 if (t is GenericTypeParameterBuilder) {
1522 TypeParameter tparam = (TypeParameter) builder_to_type_param [t];
1525 Timer.StartTimer (TimerType.FindMembers);
1526 list = tparam.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
1527 FilterWithClosure_delegate, name);
1528 Timer.StopTimer (TimerType.FindMembers);
1530 return (MemberInfo []) list;
1534 // This call will always succeed. There is exactly one TypeHandle instance per
1535 // type, TypeHandle.GetTypeHandle() will either return it or create a new one
1536 // if it didn't already exist.
1538 TypeHandle handle = TypeHandle.GetTypeHandle (t);
1541 return handle.MemberCache.FindMembers (mt, bf, name, FilterWithClosure_delegate, null);
1544 public static bool IsBuiltinType (Type t)
1546 if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
1547 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1548 t == char_type || t == short_type || t == decimal_type || t == bool_type ||
1549 t == sbyte_type || t == byte_type || t == ushort_type || t == void_type)
1555 public static bool IsBuiltinType (TypeContainer tc)
1557 return IsBuiltinType (tc.TypeBuilder);
1561 // This is like IsBuiltinType, but lacks decimal_type, we should also clean up
1562 // the pieces in the code where we use IsBuiltinType and special case decimal_type.
1564 public static bool IsCLRType (Type t)
1566 if (t == object_type || t == int32_type || t == uint32_type ||
1567 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1568 t == char_type || t == short_type || t == bool_type ||
1569 t == sbyte_type || t == byte_type || t == ushort_type)
1575 public static bool IsDelegateType (Type t)
1577 if (t.IsGenericInstance)
1578 t = t.GetGenericTypeDefinition ();
1580 if (t.IsSubclassOf (TypeManager.delegate_type))
1586 public static bool IsEnumType (Type t)
1588 if (t.IsSubclassOf (TypeManager.enum_type))
1593 public static bool IsBuiltinOrEnum (Type t)
1595 if (IsBuiltinType (t))
1605 // Only a quick hack to get things moving, while real runtime support appears
1607 public static bool IsGeneric (Type t)
1609 DeclSpace ds = (DeclSpace) builder_to_declspace [t];
1611 return ds.IsGeneric;
1614 public static bool HasGenericArguments (Type t)
1616 return GetNumberOfTypeArguments (t) > 0;
1619 public static int GetNumberOfTypeArguments (Type t)
1621 DeclSpace tc = LookupDeclSpace (t);
1623 return tc.IsGeneric ? tc.CountTypeParameters : 0;
1625 return t.HasGenericArguments ? t.GetGenericArguments ().Length : 0;
1628 public static Type[] GetTypeArguments (Type t)
1630 DeclSpace tc = LookupDeclSpace (t);
1633 throw new InvalidOperationException ();
1635 TypeParameter[] tparam = tc.TypeParameters;
1636 Type[] ret = new Type [tparam.Length];
1637 for (int i = 0; i < tparam.Length; i++) {
1638 ret [i] = tparam [i].Type;
1639 if (ret [i] == null)
1640 throw new InternalErrorException ();
1645 return t.GetGenericArguments ();
1649 // Whether a type is unmanaged. This is used by the unsafe code (25.2)
1651 public static bool IsUnmanagedType (Type t)
1653 if (IsBuiltinType (t) && t != TypeManager.string_type)
1662 if (IsValueType (t)){
1663 if (t is TypeBuilder){
1664 TypeContainer tc = LookupTypeContainer (t);
1666 if (tc.Fields != null){
1667 foreach (Field f in tc.Fields){
1668 if (f.FieldBuilder.IsStatic)
1670 if (!IsUnmanagedType (f.FieldBuilder.FieldType))
1676 FieldInfo [] fields = t.GetFields ();
1678 foreach (FieldInfo f in fields){
1681 if (!IsUnmanagedType (f.FieldType))
1691 public static bool IsValueType (Type t)
1693 return t.IsGenericParameter || t.IsValueType;
1696 public static bool IsInterfaceType (Type t)
1698 TypeContainer tc = (TypeContainer) builder_to_declspace [t];
1702 return tc.Kind == Kind.Interface;
1705 public static bool IsEqualGenericType (Type a, Type b)
1707 if ((a is TypeBuilder) && a.IsGenericTypeDefinition && b.IsGenericInstance) {
1709 // `a' is a generic type definition's TypeBuilder and `b' is a
1710 // generic instance of the same type.
1716 // void Test (Stack<T> stack) { }
1719 // The first argument of `Test' will be the generic instance
1720 // "Stack<!0>" - which is the same type than the "Stack" TypeBuilder.
1722 if (a != b.GetGenericTypeDefinition ())
1725 Type[] aparams = a.GetGenericArguments ();
1726 Type[] bparams = b.GetGenericArguments ();
1728 if (aparams.Length != bparams.Length)
1731 for (int i = 0; i < aparams.Length; i++)
1732 if (!aparams [i].Equals (bparams [i]))
1741 public static bool IsEqual (Type a, Type b)
1746 return IsEqualGenericType (a, b);
1749 public static bool MayBecomeEqualGenericTypes (Type a, Type b)
1751 if (a.IsGenericParameter) {
1753 // If a is an array of a's type, they may never
1757 b = b.GetElementType ();
1763 // If b is a generic parameter or an actual type,
1764 // they may become equal:
1766 // class X<T,U> : I<T>, I<U>
1767 // class X<T> : I<T>, I<float>
1769 if (b.IsGenericParameter || !b.IsGenericInstance)
1773 // We're now comparing a type parameter with a
1774 // generic instance. They may become equal unless
1775 // the type parameter appears anywhere in the
1776 // generic instance:
1778 // class X<T,U> : I<T>, I<X<U>>
1779 // -> error because you could instanciate it as
1782 // class X<T> : I<T>, I<X<T>> -> ok
1785 Type[] bargs = GetTypeArguments (b);
1786 for (int i = 0; i < bargs.Length; i++) {
1787 if (a.Equals (bargs [i]))
1794 if (b.IsGenericParameter)
1795 return MayBecomeEqualGenericTypes (b, a);
1798 // At this point, neither a nor b are a type parameter.
1800 // If one of them is a generic instance, let
1801 // MayBecomeEqualGenericInstances() compare them (if the
1802 // other one is not a generic instance, they can never
1806 if (a.IsGenericInstance || b.IsGenericInstance)
1807 return MayBecomeEqualGenericInstances (a, b);
1810 // If both of them are arrays.
1813 if (a.IsArray && b.IsArray) {
1814 if (a.GetArrayRank () != b.GetArrayRank ())
1817 a = a.GetElementType ();
1818 b = b.GetElementType ();
1820 return MayBecomeEqualGenericTypes (a, b);
1824 // Ok, two ordinary types.
1827 return a.Equals (b);
1831 // Checks whether two generic instances may become equal for some
1832 // particular instantiation (26.3.1).
1834 public static bool MayBecomeEqualGenericInstances (Type a, Type b)
1836 if (!a.IsGenericInstance || !b.IsGenericInstance)
1838 if (a.GetGenericTypeDefinition () != b.GetGenericTypeDefinition ())
1841 Type[] aargs = GetTypeArguments (a);
1842 Type[] bargs = GetTypeArguments (b);
1844 if (aargs.Length != bargs.Length)
1847 for (int i = 0; i < aargs.Length; i++) {
1848 if (MayBecomeEqualGenericTypes (aargs [i], bargs [i]))
1855 public static bool IsEqualGenericInstance (Type type, Type parent)
1857 int tcount = GetNumberOfTypeArguments (type);
1858 int pcount = GetNumberOfTypeArguments (parent);
1860 if (type.IsGenericInstance)
1861 type = type.GetGenericTypeDefinition ();
1862 if (parent.IsGenericInstance)
1863 parent = parent.GetGenericTypeDefinition ();
1865 if (tcount != pcount)
1868 return type.Equals (parent);
1871 public static bool IsSubclassOf (Type type, Type parent)
1874 if (IsEqualGenericInstance (type, parent))
1877 type = type.BaseType;
1878 } while (type != null);
1884 // Checks whether `type' is a subclass or nested child of `parent'.
1886 public static bool IsSubclassOrNestedChildOf (Type type, Type parent)
1889 if (IsSubclassOf (type, parent))
1892 // Handle nested types.
1893 type = type.DeclaringType;
1894 } while (type != null);
1900 // Checks whether `type' is a nested child of `parent'.
1902 public static bool IsNestedChildOf (Type type, Type parent)
1904 if (IsEqual (type, parent))
1907 type = type.DeclaringType;
1908 while (type != null) {
1909 if (IsEqual (type, parent))
1912 type = type.DeclaringType;
1919 // Do the right thing when returning the element type of an
1920 // array type based on whether we are compiling corlib or not
1922 public static Type GetElementType (Type t)
1924 if (RootContext.StdLib)
1925 return t.GetElementType ();
1927 return TypeToCoreType (t.GetElementType ());
1931 /// Returns the User Defined Types
1933 public static ArrayList UserTypes {
1939 public static Hashtable TypeContainers {
1941 return typecontainers;
1945 static Hashtable builder_to_constant;
1947 public static void RegisterConstant (FieldBuilder fb, Const c)
1949 if (builder_to_constant == null)
1950 builder_to_constant = new PtrHashtable ();
1952 if (builder_to_constant.Contains (fb))
1955 builder_to_constant.Add (fb, c);
1958 public static Const LookupConstant (FieldBuilder fb)
1960 if (builder_to_constant == null)
1963 return (Const) builder_to_constant [fb];
1967 /// Gigantic work around for missing features in System.Reflection.Emit follows.
1971 /// Since System.Reflection.Emit can not return MethodBase.GetParameters
1972 /// for anything which is dynamic, and we need this in a number of places,
1973 /// we register this information here, and use it afterwards.
1975 static public bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] args)
1980 method_arguments.Add (mb, args);
1981 method_internal_params.Add (mb, ip);
1986 static public InternalParameters LookupParametersByBuilder (MethodBase mb)
1988 if (! (mb is ConstructorBuilder || mb is MethodBuilder))
1991 if (method_internal_params.Contains (mb))
1992 return (InternalParameters) method_internal_params [mb];
1994 throw new Exception ("Argument for Method not registered" + mb);
1998 /// Returns the argument types for a method based on its methodbase
2000 /// For dynamic methods, we use the compiler provided types, for
2001 /// methods from existing assemblies we load them from GetParameters,
2002 /// and insert them into the cache
2004 static public Type [] GetArgumentTypes (MethodBase mb)
2006 object t = method_arguments [mb];
2010 ParameterInfo [] pi = mb.GetParameters ();
2017 types = new Type [c];
2018 for (int i = 0; i < c; i++)
2019 types [i] = pi [i].ParameterType;
2021 method_arguments.Add (mb, types);
2026 /// Returns the argument types for an indexer based on its PropertyInfo
2028 /// For dynamic indexers, we use the compiler provided types, for
2029 /// indexers from existing assemblies we load them from GetParameters,
2030 /// and insert them into the cache
2032 static public Type [] GetArgumentTypes (PropertyInfo indexer)
2034 if (indexer_arguments.Contains (indexer))
2035 return (Type []) indexer_arguments [indexer];
2036 else if (indexer is PropertyBuilder)
2037 // If we're a PropertyBuilder and not in the
2038 // `indexer_arguments' hash, then we're a property and
2042 ParameterInfo [] pi = indexer.GetIndexParameters ();
2043 // Property, not an indexer.
2047 Type [] types = new Type [c];
2049 for (int i = 0; i < c; i++)
2050 types [i] = pi [i].ParameterType;
2052 indexer_arguments.Add (indexer, types);
2058 // This is a workaround the fact that GetValue is not
2059 // supported for dynamic types
2061 static Hashtable fields = new Hashtable ();
2062 static public bool RegisterFieldValue (FieldBuilder fb, object value)
2064 if (fields.Contains (fb))
2067 fields.Add (fb, value);
2072 static public object GetValue (FieldBuilder fb)
2077 static Hashtable fieldbuilders_to_fields = new Hashtable ();
2078 static public bool RegisterFieldBase (FieldBuilder fb, FieldBase f)
2080 if (fieldbuilders_to_fields.Contains (fb))
2083 fieldbuilders_to_fields.Add (fb, f);
2088 // The return value can be null; This will be the case for
2089 // auxiliary FieldBuilders created by the compiler that have no
2090 // real field being declared on the source code
2092 static public FieldBase GetField (FieldInfo fb)
2094 return (FieldBase) fieldbuilders_to_fields [fb];
2097 static Hashtable events;
2099 static public bool RegisterEvent (MyEventBuilder eb, MethodBase add, MethodBase remove)
2102 events = new Hashtable ();
2104 if (events.Contains (eb))
2107 events.Add (eb, new Pair (add, remove));
2112 static public MethodInfo GetAddMethod (EventInfo ei)
2114 if (ei is MyEventBuilder) {
2115 Pair pair = (Pair) events [ei];
2117 return (MethodInfo) pair.First;
2119 return ei.GetAddMethod ();
2122 static public MethodInfo GetRemoveMethod (EventInfo ei)
2124 if (ei is MyEventBuilder) {
2125 Pair pair = (Pair) events [ei];
2127 return (MethodInfo) pair.Second;
2129 return ei.GetRemoveMethod ();
2132 static Hashtable priv_fields_events;
2134 static public bool RegisterPrivateFieldOfEvent (EventInfo einfo, FieldBuilder builder)
2136 if (priv_fields_events == null)
2137 priv_fields_events = new Hashtable ();
2139 if (priv_fields_events.Contains (einfo))
2142 priv_fields_events.Add (einfo, builder);
2147 static public MemberInfo GetPrivateFieldOfEvent (EventInfo ei)
2149 if (priv_fields_events == null)
2152 return (MemberInfo) priv_fields_events [ei];
2155 static Hashtable properties;
2157 static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set)
2159 if (properties == null)
2160 properties = new Hashtable ();
2162 if (properties.Contains (pb))
2165 properties.Add (pb, new Pair (get, set));
2170 static public bool RegisterIndexer (PropertyBuilder pb, MethodBase get,
2171 MethodBase set, Type[] args)
2173 if (!RegisterProperty (pb, get,set))
2176 indexer_arguments.Add (pb, args);
2181 public static bool CheckStructCycles (TypeContainer tc, Hashtable seen)
2183 Hashtable hash = new Hashtable ();
2184 return CheckStructCycles (tc, seen, hash);
2187 public static bool CheckStructCycles (TypeContainer tc, Hashtable seen,
2190 if ((tc.Kind != Kind.Struct) || IsBuiltinType (tc))
2194 // `seen' contains all types we've already visited.
2196 if (seen.Contains (tc))
2198 seen.Add (tc, null);
2200 if (tc.Fields == null)
2203 foreach (Field field in tc.Fields) {
2204 if (field.FieldBuilder.IsStatic)
2207 Type ftype = field.FieldBuilder.FieldType;
2208 TypeContainer ftc = LookupTypeContainer (ftype);
2212 if (hash.Contains (ftc)) {
2213 Report.Error (523, tc.Location,
2214 "Struct member `{0}.{1}' of type `{2}' " +
2215 "causes a cycle in the struct layout",
2216 tc.Name, field.Name, ftc.Name);
2221 // `hash' contains all types in the current path.
2223 hash.Add (tc, null);
2225 bool ok = CheckStructCycles (ftc, seen, hash);
2232 if (!seen.Contains (ftc))
2233 seen.Add (ftc, null);
2240 /// Given an array of interface types, expand and eliminate repeated ocurrences
2241 /// of an interface.
2245 /// This expands in context like: IA; IB : IA; IC : IA, IB; the interface "IC" to
2248 public static Type[] ExpandInterfaces (EmitContext ec, TypeExpr [] base_interfaces)
2250 ArrayList new_ifaces = new ArrayList ();
2252 foreach (TypeExpr iface in base_interfaces){
2253 Type itype = iface.ResolveType (ec);
2257 if (!new_ifaces.Contains (itype))
2258 new_ifaces.Add (itype);
2260 Type [] implementing = itype.GetInterfaces ();
2262 foreach (Type imp in implementing){
2263 if (!new_ifaces.Contains (imp))
2264 new_ifaces.Add (imp);
2267 Type [] ret = new Type [new_ifaces.Count];
2268 new_ifaces.CopyTo (ret, 0);
2272 static PtrHashtable iface_cache = new PtrHashtable ();
2275 /// This function returns the interfaces in the type `t'. Works with
2276 /// both types and TypeBuilders.
2278 public static Type [] GetInterfaces (Type t)
2281 Type [] cached = iface_cache [t] as Type [];
2286 // The reason for catching the Array case is that Reflection.Emit
2287 // will not return a TypeBuilder for Array types of TypeBuilder types,
2288 // but will still throw an exception if we try to call GetInterfaces
2291 // Since the array interfaces are always constant, we return those for
2296 t = TypeManager.array_type;
2298 if (t is TypeBuilder){
2299 Type[] parent_ifaces;
2301 if (t.BaseType == null)
2302 parent_ifaces = NoTypes;
2304 parent_ifaces = GetInterfaces (t.BaseType);
2305 Type[] type_ifaces = (Type []) builder_to_ifaces [t];
2306 if (type_ifaces == null)
2307 type_ifaces = NoTypes;
2309 int parent_count = parent_ifaces.Length;
2310 Type[] result = new Type [parent_count + type_ifaces.Length];
2311 parent_ifaces.CopyTo (result, 0);
2312 type_ifaces.CopyTo (result, parent_count);
2314 iface_cache [t] = result;
2316 } else if (t is GenericTypeParameterBuilder){
2317 Type[] type_ifaces = (Type []) builder_to_ifaces [t];
2318 if (type_ifaces == null)
2319 type_ifaces = NoTypes;
2321 iface_cache [t] = type_ifaces;
2324 Type[] ifaces = t.GetInterfaces ();
2325 iface_cache [t] = ifaces;
2331 // gets the interfaces that are declared explicitly on t
2333 public static Type [] GetExplicitInterfaces (TypeBuilder t)
2335 return (Type []) builder_to_ifaces [t];
2339 /// The following is used to check if a given type implements an interface.
2340 /// The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
2342 public static bool ImplementsInterface (Type t, Type iface)
2347 // FIXME OPTIMIZATION:
2348 // as soon as we hit a non-TypeBuiler in the interface
2349 // chain, we could return, as the `Type.GetInterfaces'
2350 // will return all the interfaces implement by the type
2354 interfaces = GetInterfaces (t);
2356 if (interfaces != null){
2357 foreach (Type i in interfaces){
2364 } while (t != null);
2369 static NumberFormatInfo nf_provider = CultureInfo.CurrentCulture.NumberFormat;
2371 // This is a custom version of Convert.ChangeType() which works
2372 // with the TypeBuilder defined types when compiling corlib.
2373 public static object ChangeType (object value, Type conversionType, out bool error)
2375 IConvertible convert_value = value as IConvertible;
2377 if (convert_value == null){
2383 // We must use Type.Equals() here since `conversionType' is
2384 // the TypeBuilder created version of a system type and not
2385 // the system type itself. You cannot use Type.GetTypeCode()
2386 // on such a type - it'd always return TypeCode.Object.
2390 if (conversionType.Equals (typeof (Boolean)))
2391 return (object)(convert_value.ToBoolean (nf_provider));
2392 else if (conversionType.Equals (typeof (Byte)))
2393 return (object)(convert_value.ToByte (nf_provider));
2394 else if (conversionType.Equals (typeof (Char)))
2395 return (object)(convert_value.ToChar (nf_provider));
2396 else if (conversionType.Equals (typeof (DateTime)))
2397 return (object)(convert_value.ToDateTime (nf_provider));
2398 else if (conversionType.Equals (typeof (Decimal)))
2399 return (object)(convert_value.ToDecimal (nf_provider));
2400 else if (conversionType.Equals (typeof (Double)))
2401 return (object)(convert_value.ToDouble (nf_provider));
2402 else if (conversionType.Equals (typeof (Int16)))
2403 return (object)(convert_value.ToInt16 (nf_provider));
2404 else if (conversionType.Equals (typeof (Int32)))
2405 return (object)(convert_value.ToInt32 (nf_provider));
2406 else if (conversionType.Equals (typeof (Int64)))
2407 return (object)(convert_value.ToInt64 (nf_provider));
2408 else if (conversionType.Equals (typeof (SByte)))
2409 return (object)(convert_value.ToSByte (nf_provider));
2410 else if (conversionType.Equals (typeof (Single)))
2411 return (object)(convert_value.ToSingle (nf_provider));
2412 else if (conversionType.Equals (typeof (String)))
2413 return (object)(convert_value.ToString (nf_provider));
2414 else if (conversionType.Equals (typeof (UInt16)))
2415 return (object)(convert_value.ToUInt16 (nf_provider));
2416 else if (conversionType.Equals (typeof (UInt32)))
2417 return (object)(convert_value.ToUInt32 (nf_provider));
2418 else if (conversionType.Equals (typeof (UInt64)))
2419 return (object)(convert_value.ToUInt64 (nf_provider));
2420 else if (conversionType.Equals (typeof (Object)))
2421 return (object)(value);
2431 // This is needed, because enumerations from assemblies
2432 // do not report their underlyingtype, but they report
2435 public static Type EnumToUnderlying (Type t)
2437 if (t == TypeManager.enum_type)
2440 t = t.UnderlyingSystemType;
2441 if (!TypeManager.IsEnumType (t))
2444 if (t is TypeBuilder) {
2445 // slow path needed to compile corlib
2446 if (t == TypeManager.bool_type ||
2447 t == TypeManager.byte_type ||
2448 t == TypeManager.sbyte_type ||
2449 t == TypeManager.char_type ||
2450 t == TypeManager.short_type ||
2451 t == TypeManager.ushort_type ||
2452 t == TypeManager.int32_type ||
2453 t == TypeManager.uint32_type ||
2454 t == TypeManager.int64_type ||
2455 t == TypeManager.uint64_type)
2457 throw new Exception ("Unhandled typecode in enum " + " from " + t.AssemblyQualifiedName);
2459 TypeCode tc = Type.GetTypeCode (t);
2462 case TypeCode.Boolean:
2463 return TypeManager.bool_type;
2465 return TypeManager.byte_type;
2466 case TypeCode.SByte:
2467 return TypeManager.sbyte_type;
2469 return TypeManager.char_type;
2470 case TypeCode.Int16:
2471 return TypeManager.short_type;
2472 case TypeCode.UInt16:
2473 return TypeManager.ushort_type;
2474 case TypeCode.Int32:
2475 return TypeManager.int32_type;
2476 case TypeCode.UInt32:
2477 return TypeManager.uint32_type;
2478 case TypeCode.Int64:
2479 return TypeManager.int64_type;
2480 case TypeCode.UInt64:
2481 return TypeManager.uint64_type;
2483 throw new Exception ("Unhandled typecode in enum " + tc + " from " + t.AssemblyQualifiedName);
2487 // When compiling corlib and called with one of the core types, return
2488 // the corresponding typebuilder for that type.
2490 public static Type TypeToCoreType (Type t)
2492 if (RootContext.StdLib || (t is TypeBuilder))
2495 TypeCode tc = Type.GetTypeCode (t);
2498 case TypeCode.Boolean:
2499 return TypeManager.bool_type;
2501 return TypeManager.byte_type;
2502 case TypeCode.SByte:
2503 return TypeManager.sbyte_type;
2505 return TypeManager.char_type;
2506 case TypeCode.Int16:
2507 return TypeManager.short_type;
2508 case TypeCode.UInt16:
2509 return TypeManager.ushort_type;
2510 case TypeCode.Int32:
2511 return TypeManager.int32_type;
2512 case TypeCode.UInt32:
2513 return TypeManager.uint32_type;
2514 case TypeCode.Int64:
2515 return TypeManager.int64_type;
2516 case TypeCode.UInt64:
2517 return TypeManager.uint64_type;
2518 case TypeCode.Single:
2519 return TypeManager.float_type;
2520 case TypeCode.Double:
2521 return TypeManager.double_type;
2522 case TypeCode.String:
2523 return TypeManager.string_type;
2525 if (t == typeof (void))
2526 return TypeManager.void_type;
2527 if (t == typeof (object))
2528 return TypeManager.object_type;
2529 if (t == typeof (System.Type))
2530 return TypeManager.type_type;
2531 if (t == typeof (System.IntPtr))
2532 return TypeManager.intptr_type;
2538 /// Utility function that can be used to probe whether a type
2539 /// is managed or not.
2541 public static bool VerifyUnManaged (Type t, Location loc)
2543 if (t.IsValueType || t.IsPointer){
2545 // FIXME: this is more complex, we actually need to
2546 // make sure that the type does not contain any
2552 if (!RootContext.StdLib && (t == TypeManager.decimal_type))
2553 // We need this explicit check here to make it work when
2554 // compiling corlib.
2559 "Cannot take the address or size of a variable of a managed type ('" +
2560 CSharpName (t) + "')");
2565 /// Returns the name of the indexer in a given type.
2568 /// The default is not always `Item'. The user can change this behaviour by
2569 /// using the DefaultMemberAttribute in the class.
2571 /// For example, the String class indexer is named `Chars' not `Item'
2573 public static string IndexerPropertyName (Type t)
2575 if (t.IsGenericInstance)
2576 t = t.GetGenericTypeDefinition ();
2578 if (t is TypeBuilder) {
2579 if (t.IsInterface) {
2580 TypeContainer i = LookupInterface (t);
2582 if ((i == null) || (i.IndexerName == null))
2585 return i.IndexerName;
2587 TypeContainer tc = LookupTypeContainer (t);
2589 if ((tc == null) || (tc.IndexerName == null))
2592 return tc.IndexerName;
2596 System.Attribute attr = System.Attribute.GetCustomAttribute (
2597 t, TypeManager.default_member_type);
2599 DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
2600 return dma.MemberName;
2606 static MethodInfo declare_local_method = null;
2608 public static LocalBuilder DeclareLocalPinned (ILGenerator ig, Type t)
2610 if (declare_local_method == null){
2611 declare_local_method = typeof (ILGenerator).GetMethod (
2613 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
2615 new Type [] { typeof (Type), typeof (bool)},
2617 if (declare_local_method == null){
2618 Report.Warning (-24, new Location (-1),
2619 "This version of the runtime does not support making pinned local variables. " +
2620 "This code may cause errors on a runtime with a moving GC");
2621 return ig.DeclareLocal (t);
2624 return (LocalBuilder) declare_local_method.Invoke (ig, new object [] { t, true });
2628 // Returns whether the array of memberinfos contains the given method
2630 public static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method)
2632 Type [] new_args = TypeManager.GetArgumentTypes (new_method);
2634 foreach (MethodBase method in array) {
2635 if (method.Name != new_method.Name)
2638 if (method is MethodInfo && new_method is MethodInfo)
2639 if (((MethodInfo) method).ReturnType != ((MethodInfo) new_method).ReturnType)
2643 Type [] old_args = TypeManager.GetArgumentTypes (method);
2644 int old_count = old_args.Length;
2647 if (new_args.Length != old_count)
2650 for (i = 0; i < old_count; i++){
2651 if (old_args [i] != new_args [i])
2664 // We copy methods from `new_members' into `target_list' if the signature
2665 // for the method from in the new list does not exist in the target_list
2667 // The name is assumed to be the same.
2669 public static ArrayList CopyNewMethods (ArrayList target_list, IList new_members)
2671 if (target_list == null){
2672 target_list = new ArrayList ();
2674 foreach (MemberInfo mi in new_members){
2675 if (mi is MethodBase)
2676 target_list.Add (mi);
2681 MemberInfo [] target_array = new MemberInfo [target_list.Count];
2682 target_list.CopyTo (target_array, 0);
2684 foreach (MemberInfo mi in new_members){
2685 MethodBase new_method = (MethodBase) mi;
2687 if (!ArrayContainsMethod (target_array, new_method))
2688 target_list.Add (new_method);
2693 static public bool IsGenericMethod (MethodBase mb)
2695 if (mb.DeclaringType is TypeBuilder) {
2696 IMethodData method = (IMethodData) builder_to_method [mb];
2700 return method.GenericMethod != null;
2703 return mb.IsGenericMethodDefinition;
2706 #region MemberLookup implementation
2709 // Whether we allow private members in the result (since FindMembers
2710 // uses NonPublic for both protected and private), we need to distinguish.
2713 static internal bool FilterNone (MemberInfo m, object filter_criteria)
2718 internal class Closure {
2719 internal bool private_ok;
2721 // Who is invoking us and which type is being queried currently.
2722 internal Type invocation_type;
2723 internal Type qualifier_type;
2725 // The assembly that defines the type is that is calling us
2726 internal Assembly invocation_assembly;
2727 internal IList almost_match;
2729 private bool CheckValidFamilyAccess (bool is_static, MemberInfo m)
2731 if (invocation_type == null)
2737 // A nested class has access to all the protected members visible
2739 if (qualifier_type != null
2740 && TypeManager.IsNestedChildOf (invocation_type, qualifier_type))
2743 if (invocation_type == m.DeclaringType
2744 || invocation_type.IsSubclassOf (m.DeclaringType)) {
2745 // Although a derived class can access protected members of
2746 // its base class it cannot do so through an instance of the
2747 // base class (CS1540).
2748 // => Ancestry should be: declaring_type ->* invocation_type
2749 // ->* qualified_type
2750 if (qualifier_type == null
2751 || qualifier_type == invocation_type
2752 || qualifier_type.IsSubclassOf (invocation_type))
2756 if (almost_match != null)
2757 almost_match.Add (m);
2761 bool Filter (MethodBase mb, object filter_criteria)
2763 MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
2765 if (ma == MethodAttributes.Private)
2766 return private_ok ||
2767 IsEqual (invocation_type, mb.DeclaringType) ||
2768 IsNestedChildOf (invocation_type, mb.DeclaringType);
2771 // FamAndAssem requires that we not only derivate, but we are on the
2774 if (ma == MethodAttributes.FamANDAssem){
2775 if (invocation_assembly != mb.DeclaringType.Assembly)
2779 // Assembly and FamORAssem succeed if we're in the same assembly.
2780 if ((ma == MethodAttributes.Assembly) || (ma == MethodAttributes.FamORAssem)){
2781 if (invocation_assembly == mb.DeclaringType.Assembly)
2785 // We already know that we aren't in the same assembly.
2786 if (ma == MethodAttributes.Assembly)
2789 // Family and FamANDAssem require that we derive.
2790 if ((ma == MethodAttributes.Family) || (ma == MethodAttributes.FamANDAssem)){
2791 if (invocation_type == null)
2794 if (!IsSubclassOrNestedChildOf (invocation_type, mb.DeclaringType))
2797 // Although a derived class can access protected members of its base class
2798 // it cannot do so through an instance of the base class (CS1540).
2799 if (!mb.IsStatic && (qualifier_type != null) &&
2800 !IsEqualGenericInstance (invocation_type, qualifier_type) &&
2801 TypeManager.IsSubclassOf (invocation_type, qualifier_type) &&
2802 !TypeManager.IsNestedChildOf (invocation_type, qualifier_type))
2812 bool Filter (FieldInfo fi, object filter_criteria)
2814 FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask;
2816 if (fa == FieldAttributes.Private)
2817 return private_ok ||
2818 IsEqual (invocation_type, fi.DeclaringType) ||
2819 IsNestedChildOf (invocation_type, fi.DeclaringType);
2822 // FamAndAssem requires that we not only derivate, but we are on the
2825 if (fa == FieldAttributes.FamANDAssem){
2826 if (invocation_assembly != fi.DeclaringType.Assembly)
2830 // Assembly and FamORAssem succeed if we're in the same assembly.
2831 if ((fa == FieldAttributes.Assembly) || (fa == FieldAttributes.FamORAssem)){
2832 if (invocation_assembly == fi.DeclaringType.Assembly)
2836 // We already know that we aren't in the same assembly.
2837 if (fa == FieldAttributes.Assembly)
2840 // Family and FamANDAssem require that we derive.
2841 if ((fa == FieldAttributes.Family) || (fa == FieldAttributes.FamANDAssem)){
2842 if (invocation_type == null)
2845 if (!IsSubclassOrNestedChildOf (invocation_type, fi.DeclaringType))
2848 // Although a derived class can access protected members of its base class
2849 // it cannot do so through an instance of the base class (CS1540).
2850 if (!fi.IsStatic && (qualifier_type != null) &&
2851 !IsEqualGenericInstance (invocation_type, qualifier_type) &&
2852 TypeManager.IsSubclassOf (invocation_type, qualifier_type) &&
2853 !TypeManager.IsNestedChildOf (invocation_type, qualifier_type))
2864 // This filter filters by name + whether it is ok to include private
2865 // members in the search
2867 internal bool Filter (MemberInfo m, object filter_criteria)
2870 // Hack: we know that the filter criteria will always be in the
2871 // `closure' // fields.
2874 if ((filter_criteria != null) && (m.Name != (string) filter_criteria))
2877 if (((qualifier_type == null) || (qualifier_type == invocation_type)) &&
2878 (invocation_type != null) &&
2879 IsEqual (m.DeclaringType, invocation_type))
2883 // Ugly: we need to find out the type of `m', and depending
2884 // on this, tell whether we accept or not
2886 if (m is MethodBase)
2887 return Filter ((MethodBase) m, filter_criteria);
2890 return Filter ((FieldInfo) m, filter_criteria);
2893 // EventInfos and PropertyInfos, return true because they lack
2894 // permission information, so we need to check later on the methods.
2900 static Closure closure = new Closure ();
2901 static MemberFilter FilterWithClosure_delegate = new MemberFilter (closure.Filter);
2902 static MemberFilter FilterNone_delegate = new MemberFilter (FilterNone);
2905 // Looks up a member called `name' in the `queried_type'. This lookup
2906 // is done by code that is contained in the definition for `invocation_type'
2907 // through a qualifier of type `qualifier_type' (or null if there is no qualifier).
2909 // `invocation_type' is used to check whether we're allowed to access the requested
2910 // member wrt its protection level.
2912 // When called from MemberAccess, `qualifier_type' is the type which is used to access
2913 // the requested member (`class B { A a = new A (); a.foo = 5; }'; here invocation_type
2914 // is B and qualifier_type is A). This is used to do the CS1540 check.
2916 // When resolving a SimpleName, `qualifier_type' is null.
2918 // The `qualifier_type' is used for the CS1540 check; it's normally either null or
2919 // the same than `queried_type' - except when we're being called from BaseAccess;
2920 // in this case, `invocation_type' is the current type and `queried_type' the base
2921 // type, so this'd normally trigger a CS1540.
2923 // The binding flags are `bf' and the kind of members being looked up are `mt'
2925 // The return value always includes private members which code in `invocation_type'
2926 // is allowed to access (using the specified `qualifier_type' if given); only use
2927 // BindingFlags.NonPublic to bypass the permission check.
2929 // The 'almost_match' argument is used for reporting error CS1540.
2931 // Returns an array of a single element for everything but Methods/Constructors
2932 // that might return multiple matches.
2934 public static MemberInfo [] MemberLookup (Type invocation_type, Type qualifier_type,
2935 Type queried_type, MemberTypes mt,
2936 BindingFlags original_bf, string name, IList almost_match)
2938 Timer.StartTimer (TimerType.MemberLookup);
2940 MemberInfo[] retval = RealMemberLookup (invocation_type, qualifier_type,
2941 queried_type, mt, original_bf, name, almost_match);
2943 Timer.StopTimer (TimerType.MemberLookup);
2948 static MemberInfo [] RealMemberLookup (Type invocation_type, Type qualifier_type,
2949 Type queried_type, MemberTypes mt,
2950 BindingFlags original_bf, string name, IList almost_match)
2952 BindingFlags bf = original_bf;
2954 ArrayList method_list = null;
2955 Type current_type = queried_type;
2956 bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0;
2957 bool skip_iface_check = true, used_cache = false;
2958 bool always_ok_flag = false;
2960 closure.invocation_type = invocation_type;
2961 closure.invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
2962 closure.qualifier_type = qualifier_type;
2963 closure.almost_match = almost_match;
2966 // If we are a nested class, we always have access to our container
2969 if (invocation_type != null){
2970 string invocation_name = invocation_type.FullName;
2971 if ((invocation_name != null) && (invocation_name.IndexOf ('+') != -1)){
2972 string container = queried_type.FullName + "+";
2973 int container_length = container.Length;
2975 if (invocation_name.Length > container_length){
2976 string shared = invocation_name.Substring (0, container_length);
2978 if (shared == container)
2979 always_ok_flag = true;
2984 // This is from the first time we find a method
2985 // in most cases, we do not actually find a method in the base class
2986 // so we can just ignore it, and save the arraylist allocation
2987 MemberInfo [] first_members_list = null;
2988 bool use_first_members_list = false;
2994 // `NonPublic' is lame, because it includes both protected and
2995 // private methods, so we need to control this behavior by
2996 // explicitly tracking if a private method is ok or not.
2998 // The possible cases are:
2999 // public, private and protected (internal does not come into the
3002 if ((invocation_type != null) &&
3003 ((invocation_type == current_type) ||
3004 IsNestedChildOf (invocation_type, current_type)) ||
3006 bf = original_bf | BindingFlags.NonPublic;
3010 closure.private_ok = (original_bf & BindingFlags.NonPublic) != 0;
3012 Timer.StopTimer (TimerType.MemberLookup);
3014 list = MemberLookup_FindMembers (
3015 current_type, mt, bf, name, out used_cache);
3017 Timer.StartTimer (TimerType.MemberLookup);
3020 // When queried for an interface type, the cache will automatically check all
3021 // inherited members, so we don't need to do this here. However, this only
3022 // works if we already used the cache in the first iteration of this loop.
3024 // If we used the cache in any further iteration, we can still terminate the
3025 // loop since the cache always looks in all parent classes.
3031 skip_iface_check = false;
3033 if (current_type == TypeManager.object_type)
3036 current_type = current_type.BaseType;
3039 // This happens with interfaces, they have a null
3040 // basetype. Look members up in the Object class.
3042 if (current_type == null)
3043 current_type = TypeManager.object_type;
3046 if (list.Length == 0)
3050 // Events and types are returned by both `static' and `instance'
3051 // searches, which means that our above FindMembers will
3052 // return two copies of the same.
3054 if (list.Length == 1 && !(list [0] is MethodBase)){
3059 // Multiple properties: we query those just to find out the indexer
3062 if (list [0] is PropertyInfo)
3066 // We found an event: the cache lookup returns both the event and
3067 // its private field.
3069 if (list [0] is EventInfo) {
3070 if ((list.Length == 2) && (list [1] is FieldInfo))
3071 return new MemberInfo [] { list [0] };
3078 // We found methods, turn the search into "method scan"
3082 if (first_members_list != null) {
3083 if (use_first_members_list) {
3084 method_list = CopyNewMethods (method_list, first_members_list);
3085 use_first_members_list = false;
3088 method_list = CopyNewMethods (method_list, list);
3090 first_members_list = list;
3091 use_first_members_list = true;
3093 mt &= (MemberTypes.Method | MemberTypes.Constructor);
3095 } while (searching);
3097 if (use_first_members_list) {
3098 foreach (MemberInfo mi in first_members_list) {
3099 if (! (mi is MethodBase)) {
3100 method_list = CopyNewMethods (method_list, first_members_list);
3101 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
3104 return (MemberInfo []) first_members_list;
3107 if (method_list != null && method_list.Count > 0) {
3108 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
3111 // This happens if we already used the cache in the first iteration, in this case
3112 // the cache already looked in all interfaces.
3114 if (skip_iface_check)
3118 // Interfaces do not list members they inherit, so we have to
3121 if (!queried_type.IsInterface)
3124 if (queried_type.IsArray)
3125 queried_type = TypeManager.array_type;
3127 Type [] ifaces = GetInterfaces (queried_type);
3131 foreach (Type itype in ifaces){
3134 x = MemberLookup (null, null, itype, mt, bf, name, null);
3143 // This is used to extract properties and event declarations from a type
3145 static MemberInfo [] SpecialContainerLookup (Type t, bool is_static)
3147 BindingFlags bf = BindingFlags.DeclaredOnly | (is_static ? BindingFlags.Static : BindingFlags.Instance);
3149 bf |= BindingFlags.Public | BindingFlags.NonPublic;
3151 if (t is TypeBuilder) {
3152 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
3154 return (MemberInfo []) decl.FindMembers (
3155 MemberTypes.Property | MemberTypes.Event,
3156 bf, FilterNone_delegate, null);
3158 return t.FindMembers (MemberTypes.Property | MemberTypes.Event,
3159 bf, FilterNone_delegate, null);
3164 public static bool IsSpecialMethod (MethodBase mb)
3166 Type t = mb.DeclaringType;
3168 MemberInfo [] matches = TypeManager.SpecialContainerLookup (t, mb.IsStatic);
3169 if (matches == null)
3172 foreach (MemberInfo mi in matches){
3173 if (mi is PropertyBuilder){
3174 Pair p = (Pair) properties [mi];
3176 if (p.First == mb || p.Second == mb)
3178 } else if (mi is PropertyInfo){
3179 MethodInfo [] methods = ((PropertyInfo) mi).GetAccessors (true);
3181 foreach (MethodInfo m in methods){
3185 } else if (mi is MyEventBuilder){
3186 Pair p = (Pair) events [mi];
3188 if (p.First == mb || p.Second == mb)
3190 } else if (mi is EventInfo){
3191 EventInfo ei = ((EventInfo) mi);
3193 if (ei.GetAddMethod (true) == mb)
3196 if (ei.GetRemoveMethod (true) == mb)
3199 if (ei.GetRaiseMethod (true) == mb)
3205 // Now check if it is an operator method
3209 if (s.StartsWith ("op_")){
3210 foreach (string name in Unary.oper_names){
3215 foreach (string name in Binary.oper_names){
3229 /// There is exactly one instance of this class per type.
3231 public sealed class TypeHandle : IMemberContainer {
3232 public readonly TypeHandle BaseType;
3234 readonly int id = ++next_id;
3235 static int next_id = 0;
3238 /// Lookup a TypeHandle instance for the given type. If the type doesn't have
3239 /// a TypeHandle yet, a new instance of it is created. This static method
3240 /// ensures that we'll only have one TypeHandle instance per type.
3242 public static TypeHandle GetTypeHandle (Type t)
3244 TypeHandle handle = (TypeHandle) type_hash [t];
3248 handle = new TypeHandle (t);
3249 type_hash.Add (t, handle);
3253 public static void CleanUp ()
3259 /// Returns the TypeHandle for TypeManager.object_type.
3261 public static IMemberContainer ObjectType {
3263 if (object_type != null)
3266 object_type = GetTypeHandle (TypeManager.object_type);
3273 /// Returns the TypeHandle for TypeManager.array_type.
3275 public static IMemberContainer ArrayType {
3277 if (array_type != null)
3280 array_type = GetTypeHandle (TypeManager.array_type);
3286 private static PtrHashtable type_hash = new PtrHashtable ();
3288 private static TypeHandle object_type = null;
3289 private static TypeHandle array_type = null;
3292 private string full_name;
3293 private bool is_interface;
3294 private MemberCache member_cache;
3296 private TypeHandle (Type type)
3299 full_name = type.FullName != null ? type.FullName : type.Name;
3300 if (type.BaseType != null)
3301 BaseType = GetTypeHandle (type.BaseType);
3302 this.is_interface = type.IsInterface || type.IsGenericParameter;
3303 this.member_cache = new MemberCache (this);
3306 // IMemberContainer methods
3308 public string Name {
3320 public IMemberContainer Parent {
3326 public bool IsInterface {
3328 return is_interface;
3332 public MemberList GetMembers (MemberTypes mt, BindingFlags bf)
3334 MemberInfo [] members;
3335 if (type is GenericTypeParameterBuilder)
3336 return MemberList.Empty;
3337 if (mt == MemberTypes.Event)
3338 members = type.GetEvents (bf | BindingFlags.DeclaredOnly);
3340 members = type.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
3342 Array.Reverse (members);
3344 return new MemberList (members);
3347 // IMemberFinder methods
3349 public MemberList FindMembers (MemberTypes mt, BindingFlags bf, string name,
3350 MemberFilter filter, object criteria)
3352 return new MemberList (member_cache.FindMembers (mt, bf, name, filter, criteria));
3355 public MemberCache MemberCache {
3357 return member_cache;
3361 public override string ToString ()
3363 if (BaseType != null)
3364 return "TypeHandle (" + id + "," + Name + " : " + BaseType + ")";
3366 return "TypeHandle (" + id + "," + Name + ")";