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;
187 static public ConstructorInfo default_member_ctor;
190 // Holds the Array of Assemblies that have been loaded
191 // (either because it is the default or the user used the
192 // -r command line option)
194 static Assembly [] assemblies;
197 // Keeps a list of modules. We used this to do lookups
198 // on the module using GetType -- needed for arrays
200 static Module [] modules;
203 // This is the type_cache from the assemblies to avoid
204 // hitting System.Reflection on every lookup.
206 static Hashtable types;
209 // This is used to hotld the corresponding TypeContainer objects
210 // since we need this in FindMembers
212 static Hashtable typecontainers;
215 // Keeps track of those types that are defined by the
218 static ArrayList user_types;
220 static PtrHashtable builder_to_declspace;
223 // Tracks the interfaces implemented by typebuilders. We only
224 // enter those who do implement or or more interfaces
226 static PtrHashtable builder_to_ifaces;
229 // Tracks the generic parameters.
231 static PtrHashtable builder_to_type_param;
234 // Maps MethodBase.RuntimeTypeHandle to a Type array that contains
235 // the arguments to the method
237 static Hashtable method_arguments;
240 // Maps PropertyBuilder to a Type array that contains
241 // the arguments to the indexer
243 static Hashtable indexer_arguments;
246 // Maybe `method_arguments' should be replaced and only
247 // method_internal_params should be kept?
249 static Hashtable method_internal_params;
252 // Keeps track of methods
255 static Hashtable builder_to_method;
258 // Contains all public types from referenced assemblies.
259 // This member is used only if CLS Compliance verification is required.
261 public static Hashtable all_imported_types;
268 public static void CleanUp ()
270 // Lets get everything clean so that we can collect before generating code
274 typecontainers = null;
276 builder_to_declspace = null;
277 builder_to_ifaces = null;
278 method_arguments = null;
279 indexer_arguments = null;
280 method_internal_params = null;
281 builder_to_method = null;
282 builder_to_type_param = null;
286 negative_hits = null;
287 builder_to_constant = null;
288 fieldbuilders_to_fields = null;
290 priv_fields_events = null;
293 TypeHandle.CleanUp ();
297 /// A filter for Findmembers that uses the Signature object to
300 static bool SignatureFilter (MemberInfo mi, object criteria)
302 Signature sig = (Signature) criteria;
304 if (!(mi is MethodBase))
307 if (mi.Name != sig.name)
310 int count = sig.args.Length;
312 if (mi is MethodBuilder || mi is ConstructorBuilder){
313 Type [] candidate_args = GetArgumentTypes ((MethodBase) mi);
315 if (candidate_args.Length != count)
318 for (int i = 0; i < count; i++)
319 if (candidate_args [i] != sig.args [i])
324 ParameterInfo [] pars = ((MethodBase) mi).GetParameters ();
326 if (pars.Length != count)
329 for (int i = 0; i < count; i++)
330 if (pars [i].ParameterType != sig.args [i])
336 // A delegate that points to the filter above.
337 static MemberFilter signature_filter;
340 // These are expressions that represent some of the internal data types, used
343 static void InitExpressionTypes ()
345 system_object_expr = new TypeLookupExpression ("System.Object");
346 system_string_expr = new TypeLookupExpression ("System.String");
347 system_boolean_expr = new TypeLookupExpression ("System.Boolean");
348 system_decimal_expr = new TypeLookupExpression ("System.Decimal");
349 system_single_expr = new TypeLookupExpression ("System.Single");
350 system_double_expr = new TypeLookupExpression ("System.Double");
351 system_sbyte_expr = new TypeLookupExpression ("System.SByte");
352 system_byte_expr = new TypeLookupExpression ("System.Byte");
353 system_int16_expr = new TypeLookupExpression ("System.Int16");
354 system_uint16_expr = new TypeLookupExpression ("System.UInt16");
355 system_int32_expr = new TypeLookupExpression ("System.Int32");
356 system_uint32_expr = new TypeLookupExpression ("System.UInt32");
357 system_int64_expr = new TypeLookupExpression ("System.Int64");
358 system_uint64_expr = new TypeLookupExpression ("System.UInt64");
359 system_char_expr = new TypeLookupExpression ("System.Char");
360 system_void_expr = new TypeLookupExpression ("System.Void");
361 system_asynccallback_expr = new TypeLookupExpression ("System.AsyncCallback");
362 system_iasyncresult_expr = new TypeLookupExpression ("System.IAsyncResult");
363 system_valuetype_expr = new TypeLookupExpression ("System.ValueType");
366 static TypeManager ()
368 assemblies = new Assembly [0];
370 user_types = new ArrayList ();
372 types = new Hashtable ();
373 typecontainers = new Hashtable ();
375 builder_to_declspace = new PtrHashtable ();
376 builder_to_method = new PtrHashtable ();
377 method_arguments = new PtrHashtable ();
378 method_internal_params = new PtrHashtable ();
379 indexer_arguments = new PtrHashtable ();
380 builder_to_ifaces = new PtrHashtable ();
381 builder_to_type_param = new PtrHashtable ();
383 NoTypes = new Type [0];
384 NoTypeExprs = new TypeExpr [0];
386 signature_filter = new MemberFilter (SignatureFilter);
387 InitExpressionTypes ();
390 public static void HandleDuplicate (string name, Type t)
392 Type prev = (Type) types [name];
393 TypeContainer tc = builder_to_declspace [prev] as TypeContainer;
397 // This probably never happens, as we catch this before
399 Report.Error (-17, "The type `" + name + "' has already been defined.");
403 tc = builder_to_declspace [t] as TypeContainer;
406 1595, "The type `" + name + "' is defined in an existing assembly;"+
407 " Using the new definition from: " + tc.Location);
410 1595, "The type `" + name + "' is defined in an existing assembly;");
413 Report.Warning (1595, "Previously defined in: " + prev.Assembly.FullName);
419 public static void AddUserType (string name, TypeBuilder t)
424 HandleDuplicate (name, t);
430 // This entry point is used by types that we define under the covers
432 public static void RegisterBuilder (Type tb, Type [] ifaces)
435 builder_to_ifaces [tb] = ifaces;
438 public static void AddUserType (string name, TypeBuilder t, TypeContainer tc)
440 builder_to_declspace.Add (t, tc);
441 typecontainers.Add (name, tc);
442 AddUserType (name, t);
445 public static void AddDelegateType (string name, TypeBuilder t, Delegate del)
450 HandleDuplicate (name, t);
453 builder_to_declspace.Add (t, del);
456 public static void AddEnumType (string name, TypeBuilder t, Enum en)
461 HandleDuplicate (name, t);
463 builder_to_declspace.Add (t, en);
466 public static void AddMethod (MethodBase builder, IMethodData method)
468 builder_to_method.Add (builder, method);
471 public static IMethodData GetMethod (MethodBase builder)
473 return (IMethodData) builder_to_method [builder];
476 public static void AddTypeParameter (Type t, TypeParameter tparam)
478 if (!builder_to_type_param.Contains (t))
479 builder_to_type_param.Add (t, tparam);
483 /// Returns the DeclSpace whose Type is `t' or null if there is no
484 /// DeclSpace for `t' (ie, the Type comes from a library)
486 public static DeclSpace LookupDeclSpace (Type t)
488 return builder_to_declspace [t] as DeclSpace;
492 /// Returns the TypeContainer whose Type is `t' or null if there is no
493 /// TypeContainer for `t' (ie, the Type comes from a library)
495 public static TypeContainer LookupTypeContainer (Type t)
497 return builder_to_declspace [t] as TypeContainer;
500 public static IMemberContainer LookupMemberContainer (Type t)
502 if (t is TypeBuilder) {
503 IMemberContainer container = builder_to_declspace [t] as IMemberContainer;
504 if (container != null)
508 if (t is GenericTypeParameterBuilder) {
509 IMemberContainer container = builder_to_type_param [t] as IMemberContainer;
511 if (container != null)
515 return TypeHandle.GetTypeHandle (t);
518 public static TypeContainer LookupInterface (Type t)
520 TypeContainer tc = (TypeContainer) builder_to_declspace [t];
521 if ((tc == null) || (tc.Kind != Kind.Interface))
527 public static Delegate LookupDelegate (Type t)
529 return builder_to_declspace [t] as Delegate;
532 public static Enum LookupEnum (Type t)
534 return builder_to_declspace [t] as Enum;
537 public static Class LookupClass (Type t)
539 return (Class) builder_to_declspace [t];
542 public static TypeParameter LookupTypeParameter (Type t)
544 return (TypeParameter) builder_to_type_param [t];
547 public static bool HasConstructorConstraint (Type t)
549 if (!t.IsGenericParameter)
550 throw new InvalidOperationException ();
552 TypeParameter tparam = LookupTypeParameter (t);
554 return tparam.HasConstructorConstraint;
556 object[] attrs = t.GetCustomAttributes (
557 TypeManager.new_constraint_attr_type, false);
559 return attrs.Length > 0;
564 /// Registers an assembly to load types from.
566 public static void AddAssembly (Assembly a)
568 foreach (Assembly assembly in assemblies) {
573 int top = assemblies.Length;
574 Assembly [] n = new Assembly [top + 1];
576 assemblies.CopyTo (n, 0);
582 public static Assembly [] GetAssemblies ()
588 /// Registers a module builder to lookup types from
590 public static void AddModule (Module mb)
592 int top = modules != null ? modules.Length : 0;
593 Module [] n = new Module [top + 1];
596 modules.CopyTo (n, 0);
601 public static Module[] Modules {
607 static Hashtable references = new Hashtable ();
610 // Gets the reference to T version of the Type (T&)
612 public static Type GetReferenceType (Type t)
614 return t.MakeByRefType ();
617 static Hashtable pointers = new Hashtable ();
620 // Gets the pointer to T version of the Type (T*)
622 public static Type GetPointerType (Type t)
624 string tname = t.FullName + "*";
626 Type ret = t.Assembly.GetType (tname);
629 // If the type comes from the assembly we are building
630 // We need the Hashtable, because .NET 1.1 will return different instance types
631 // every time we call ModuleBuilder.GetType.
634 if (pointers [t] == null)
635 pointers [t] = CodeGen.Module.Builder.GetType (tname);
637 ret = (Type) pointers [t];
644 // Low-level lookup, cache-less
646 static Type LookupTypeReflection (string name)
650 foreach (Assembly a in assemblies){
651 t = a.GetType (name);
656 TypeAttributes ta = t.Attributes & TypeAttributes.VisibilityMask;
657 if (ta == TypeAttributes.NotPublic ||
658 ta == TypeAttributes.NestedPrivate ||
659 ta == TypeAttributes.NestedAssembly ||
660 ta == TypeAttributes.NestedFamANDAssem){
663 // In .NET pointers turn out to be private, even if their
664 // element type is not
667 t = t.GetElementType ();
677 foreach (Module mb in modules) {
678 t = mb.GetType (name);
686 static Hashtable negative_hits = new Hashtable ();
689 // This function is used when you want to avoid the lookups, and want to go
690 // directly to the source. This will use the cache.
692 // Notice that bypassing the cache is bad, because on Microsoft.NET runtime
693 // GetType ("DynamicType[]") != GetType ("DynamicType[]"), and there is no
694 // way to test things other than doing a fullname compare
696 public static Type LookupTypeDirect (string name)
698 Type t = (Type) types [name];
702 t = LookupTypeReflection (name);
710 static readonly char [] dot_array = { '.' };
713 /// Returns the Type associated with @name, takes care of the fact that
714 /// reflection expects nested types to be separated from the main type
715 /// with a "+" instead of a "."
717 public static Type LookupType (string name)
722 // First lookup in user defined and cached values
725 t = (Type) types [name];
729 // Two thirds of the failures are caught here.
730 if (negative_hits.Contains (name))
733 // Sadly, split takes a param array, so this ends up allocating *EVERY TIME*
734 string [] elements = name.Split (dot_array);
735 int count = elements.Length;
737 for (int n = 1; n <= count; n++){
738 string top_level_type = String.Join (".", elements, 0, n);
740 // One third of the failures are caught here.
741 if (negative_hits.Contains (top_level_type))
744 t = (Type) types [top_level_type];
746 t = LookupTypeReflection (top_level_type);
748 negative_hits [top_level_type] = null;
759 // We know that System.Object does not have children, and since its the parent of
760 // all the objects, it always gets probbed for inner classes.
762 if (top_level_type == "System.Object")
765 string newt = top_level_type + "+" + String.Join ("+", elements, n, count - n);
766 //Console.WriteLine ("Looking up: " + newt + " " + name);
767 t = LookupTypeReflection (newt);
769 negative_hits [name] = null;
774 negative_hits [name] = null;
779 /// Computes the namespaces that we import from the assemblies we reference.
781 public static void ComputeNamespaces ()
783 MethodInfo assembly_get_namespaces = typeof (Assembly).GetMethod ("GetNamespaces", BindingFlags.Instance|BindingFlags.NonPublic);
786 // First add the assembly namespaces
788 if (assembly_get_namespaces != null){
789 int count = assemblies.Length;
791 for (int i = 0; i < count; i++){
792 Assembly a = assemblies [i];
793 string [] namespaces = (string []) assembly_get_namespaces.Invoke (a, null);
794 foreach (string ns in namespaces){
797 Namespace.LookupNamespace (ns, true);
801 Hashtable cache = new Hashtable ();
802 cache.Add ("", null);
803 foreach (Assembly a in assemblies) {
804 foreach (Type t in a.GetExportedTypes ()) {
805 string ns = t.Namespace;
806 if (ns == null || cache.Contains (ns))
809 Namespace.LookupNamespace (ns, true);
810 cache.Add (ns, null);
817 /// Fills static table with exported types from all referenced assemblies.
818 /// This information is required for CLS Compliance tests.
820 public static void LoadAllImportedTypes ()
822 all_imported_types = new Hashtable ();
823 foreach (Assembly a in assemblies) {
824 foreach (Type t in a.GetExportedTypes ()) {
825 all_imported_types [t.FullName] = t;
830 public static bool NamespaceClash (string name, Location loc)
832 if (Namespace.LookupNamespace (name, false) == null)
835 Report.Error (519, loc, String.Format ("`{0}' clashes with a predefined namespace", name));
840 /// Returns the C# name of a type if possible, or the full type name otherwise
842 static public string CSharpName (Type t)
844 if (t.FullName == null)
847 return Regex.Replace (t.FullName,
849 @"(Int32|UInt32|Int16|UInt16|Int64|UInt64|" +
850 @"Single|Double|Char|Decimal|Byte|SByte|Object|" +
851 @"Boolean|String|Void|Null)" +
853 new MatchEvaluator (CSharpNameMatch));
856 static String CSharpNameMatch (Match match)
858 string s = match.Groups [1].Captures [0].Value;
860 Replace ("int32", "int").
861 Replace ("uint32", "uint").
862 Replace ("int16", "short").
863 Replace ("uint16", "ushort").
864 Replace ("int64", "long").
865 Replace ("uint64", "ulong").
866 Replace ("single", "float").
867 Replace ("boolean", "bool")
868 + match.Groups [2].Captures [0].Value;
872 /// Returns the signature of the method with full namespace classification
874 static public string GetFullNameSignature (MemberInfo mi)
876 return mi.DeclaringType.FullName.Replace ('+', '.') + '.' + mi.Name;
879 static public string GetFullNameSignature (MethodBase mb)
881 string name = mb.Name;
883 name = mb.DeclaringType.Name;
885 if (mb.IsSpecialName) {
886 if (name.StartsWith ("get_") || name.StartsWith ("set_")) {
887 name = name.Remove (0, 4);
894 return mb.DeclaringType.FullName.Replace ('+', '.') + '.' + name;
897 static public string GetFullName (Type t)
899 if (t.FullName == null)
902 string name = t.FullName.Replace ('+', '.');
904 DeclSpace tc = LookupDeclSpace (t);
905 if ((tc != null) && tc.IsGeneric) {
906 TypeParameter[] tparam = tc.TypeParameters;
908 StringBuilder sb = new StringBuilder (name);
910 for (int i = 0; i < tparam.Length; i++) {
913 sb.Append (tparam [i].Name);
916 return sb.ToString ();
917 } else if (t.HasGenericArguments && !t.IsGenericInstance) {
918 Type[] tparam = t.GetGenericArguments ();
920 StringBuilder sb = new StringBuilder (name);
922 for (int i = 0; i < tparam.Length; i++) {
925 sb.Append (tparam [i].Name);
928 return sb.ToString ();
935 /// Returns the signature of the property and indexer
937 static public string CSharpSignature (PropertyBuilder pb, bool is_indexer)
940 return GetFullNameSignature (pb);
943 MethodBase mb = pb.GetSetMethod (true) != null ? pb.GetSetMethod (true) : pb.GetGetMethod (true);
944 string signature = GetFullNameSignature (mb);
945 string arg = TypeManager.LookupParametersByBuilder (mb).ParameterDesc (0);
946 return String.Format ("{0}.this[{1}]", signature.Substring (0, signature.LastIndexOf ('.')), arg);
950 /// Returns the signature of the method
952 static public string CSharpSignature (MethodBase mb)
954 StringBuilder sig = new StringBuilder ("(");
957 // FIXME: We should really have a single function to do
958 // everything instead of the following 5 line pattern
960 ParameterData iparams = LookupParametersByBuilder (mb);
963 iparams = new ReflectionParameters (mb);
966 if (mb.IsSpecialName && iparams.Count == 0 && !mb.IsConstructor)
967 return GetFullNameSignature (mb);
969 for (int i = 0; i < iparams.Count; i++) {
973 sig.Append (iparams.ParameterDesc (i));
978 if (mb.IsSpecialName && iparams.Count == 1 && !mb.IsConstructor) {
979 sig.Replace ('(', '[');
980 sig.Replace (')', ']');
983 return GetFullNameSignature (mb) + sig.ToString ();
987 /// Looks up a type, and aborts if it is not found. This is used
988 /// by types required by the compiler
990 static Type CoreLookupType (string name)
992 Type t = LookupTypeDirect (name);
995 Report.Error (518, "The predefined type `" + name + "' is not defined or imported");
996 Environment.Exit (1);
1003 /// Returns the MethodInfo for a method named `name' defined
1004 /// in type `t' which takes arguments of types `args'
1006 static MethodInfo GetMethod (Type t, string name, Type [] args, bool is_private, bool report_errors)
1010 BindingFlags flags = instance_and_static | BindingFlags.Public;
1016 flags |= BindingFlags.NonPublic;
1018 list = FindMembers (t, MemberTypes.Method, flags, signature_filter, sig);
1019 if (list.Count == 0) {
1021 Report.Error (-19, "Can not find the core function `" + name + "'");
1025 MethodInfo mi = list [0] as MethodInfo;
1028 Report.Error (-19, "Can not find the core function `" + name + "'");
1035 static MethodInfo GetMethod (Type t, string name, Type [] args, bool report_errors)
1037 return GetMethod (t, name, args, false, report_errors);
1040 static MethodInfo GetMethod (Type t, string name, Type [] args)
1042 return GetMethod (t, name, args, true);
1047 /// Returns the ConstructorInfo for "args"
1049 static ConstructorInfo GetConstructor (Type t, Type [] args)
1057 list = FindMembers (t, MemberTypes.Constructor,
1058 instance_and_static | BindingFlags.Public | BindingFlags.DeclaredOnly,
1059 signature_filter, sig);
1060 if (list.Count == 0){
1061 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
1065 ConstructorInfo ci = list [0] as ConstructorInfo;
1067 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
1074 public static void InitEnumUnderlyingTypes ()
1077 int32_type = CoreLookupType ("System.Int32");
1078 int64_type = CoreLookupType ("System.Int64");
1079 uint32_type = CoreLookupType ("System.UInt32");
1080 uint64_type = CoreLookupType ("System.UInt64");
1081 byte_type = CoreLookupType ("System.Byte");
1082 sbyte_type = CoreLookupType ("System.SByte");
1083 short_type = CoreLookupType ("System.Int16");
1084 ushort_type = CoreLookupType ("System.UInt16");
1088 /// The types have to be initialized after the initial
1089 /// population of the type has happened (for example, to
1090 /// bootstrap the corlib.dll
1092 public static void InitCoreTypes ()
1094 object_type = CoreLookupType ("System.Object");
1095 value_type = CoreLookupType ("System.ValueType");
1097 InitEnumUnderlyingTypes ();
1099 char_type = CoreLookupType ("System.Char");
1100 string_type = CoreLookupType ("System.String");
1101 float_type = CoreLookupType ("System.Single");
1102 double_type = CoreLookupType ("System.Double");
1103 char_ptr_type = CoreLookupType ("System.Char*");
1104 decimal_type = CoreLookupType ("System.Decimal");
1105 bool_type = CoreLookupType ("System.Boolean");
1106 enum_type = CoreLookupType ("System.Enum");
1108 multicast_delegate_type = CoreLookupType ("System.MulticastDelegate");
1109 delegate_type = CoreLookupType ("System.Delegate");
1111 array_type = CoreLookupType ("System.Array");
1112 void_type = CoreLookupType ("System.Void");
1113 type_type = CoreLookupType ("System.Type");
1115 runtime_field_handle_type = CoreLookupType ("System.RuntimeFieldHandle");
1116 runtime_argument_handle_type = CoreLookupType ("System.RuntimeArgumentHandle");
1117 runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices.RuntimeHelpers");
1118 default_member_type = CoreLookupType ("System.Reflection.DefaultMemberAttribute");
1119 runtime_handle_type = CoreLookupType ("System.RuntimeTypeHandle");
1120 asynccallback_type = CoreLookupType ("System.AsyncCallback");
1121 iasyncresult_type = CoreLookupType ("System.IAsyncResult");
1122 ienumerator_type = CoreLookupType ("System.Collections.IEnumerator");
1123 ienumerable_type = CoreLookupType ("System.Collections.IEnumerable");
1124 idisposable_type = CoreLookupType ("System.IDisposable");
1125 icloneable_type = CoreLookupType ("System.ICloneable");
1126 iconvertible_type = CoreLookupType ("System.IConvertible");
1127 monitor_type = CoreLookupType ("System.Threading.Monitor");
1128 intptr_type = CoreLookupType ("System.IntPtr");
1130 attribute_type = CoreLookupType ("System.Attribute");
1131 attribute_usage_type = CoreLookupType ("System.AttributeUsageAttribute");
1132 dllimport_type = CoreLookupType ("System.Runtime.InteropServices.DllImportAttribute");
1133 methodimpl_attr_type = CoreLookupType ("System.Runtime.CompilerServices.MethodImplAttribute");
1134 marshal_as_attr_type = CoreLookupType ("System.Runtime.InteropServices.MarshalAsAttribute");
1135 new_constraint_attr_type = CoreLookupType ("System.Runtime.CompilerServices.NewConstraintAttribute");
1136 param_array_type = CoreLookupType ("System.ParamArrayAttribute");
1137 in_attribute_type = CoreLookupType ("System.Runtime.InteropServices.InAttribute");
1138 typed_reference_type = CoreLookupType ("System.TypedReference");
1139 arg_iterator_type = CoreLookupType ("System.ArgIterator");
1140 mbr_type = CoreLookupType ("System.MarshalByRefObject");
1143 // Sigh. Remove this before the release. Wonder what versions of Mono
1144 // people are running.
1146 guid_attr_type = LookupType ("System.Runtime.InteropServices.GuidAttribute");
1148 unverifiable_code_type= CoreLookupType ("System.Security.UnverifiableCodeAttribute");
1150 void_ptr_type = CoreLookupType ("System.Void*");
1152 indexer_name_type = CoreLookupType ("System.Runtime.CompilerServices.IndexerNameAttribute");
1154 exception_type = CoreLookupType ("System.Exception");
1155 activator_type = CoreLookupType ("System.Activator");
1156 invalid_operation_exception_type = CoreLookupType ("System.InvalidOperationException");
1157 not_supported_exception_type = CoreLookupType ("System.NotSupportedException");
1162 obsolete_attribute_type = CoreLookupType ("System.ObsoleteAttribute");
1163 conditional_attribute_type = CoreLookupType ("System.Diagnostics.ConditionalAttribute");
1164 cls_compliant_attribute_type = CoreLookupType ("System.CLSCompliantAttribute");
1165 struct_layout_attribute_type = CoreLookupType ("System.Runtime.InteropServices.StructLayoutAttribute");
1166 field_offset_attribute_type = CoreLookupType ("System.Runtime.InteropServices.FieldOffsetAttribute");
1171 generic_ienumerator_type = CoreLookupType (MemberName.MakeName ("System.Collections.Generic.IEnumerator", 1));
1172 generic_ienumerable_type = CoreLookupType (MemberName.MakeName ("System.Collections.Generic.IEnumerable", 1));
1176 // When compiling corlib, store the "real" types here.
1178 if (!RootContext.StdLib) {
1179 system_int32_type = typeof (System.Int32);
1180 system_array_type = typeof (System.Array);
1181 system_type_type = typeof (System.Type);
1182 system_assemblybuilder_type = typeof (System.Reflection.Emit.AssemblyBuilder);
1184 Type [] void_arg = { };
1185 system_int_array_get_length = GetMethod (
1186 system_array_type, "get_Length", void_arg);
1187 system_int_array_get_rank = GetMethod (
1188 system_array_type, "get_Rank", void_arg);
1189 system_object_array_clone = GetMethod (
1190 system_array_type, "Clone", void_arg);
1192 Type [] system_int_arg = { system_int32_type };
1193 system_int_array_get_length_int = GetMethod (
1194 system_array_type, "GetLength", system_int_arg);
1195 system_int_array_get_upper_bound_int = GetMethod (
1196 system_array_type, "GetUpperBound", system_int_arg);
1197 system_int_array_get_lower_bound_int = GetMethod (
1198 system_array_type, "GetLowerBound", system_int_arg);
1200 Type [] system_array_int_arg = { system_array_type, system_int32_type };
1201 system_void_array_copyto_array_int = GetMethod (
1202 system_array_type, "CopyTo", system_array_int_arg);
1204 Type [] system_3_type_arg = {
1205 system_type_type, system_type_type, system_type_type };
1206 Type [] system_4_type_arg = {
1207 system_type_type, system_type_type, system_type_type, system_type_type };
1209 MethodInfo set_corlib_type_builders = GetMethod (
1210 system_assemblybuilder_type, "SetCorlibTypeBuilders",
1211 system_4_type_arg, true, false);
1213 if (set_corlib_type_builders != null) {
1214 object[] args = new object [4];
1215 args [0] = object_type;
1216 args [1] = value_type;
1217 args [2] = enum_type;
1218 args [3] = void_type;
1220 set_corlib_type_builders.Invoke (CodeGen.Assembly.Builder, args);
1222 // Compatibility for an older version of the class libs.
1223 set_corlib_type_builders = GetMethod (
1224 system_assemblybuilder_type, "SetCorlibTypeBuilders",
1225 system_3_type_arg, true, true);
1227 if (set_corlib_type_builders == null) {
1228 Report.Error (-26, "Corlib compilation is not supported in Microsoft.NET due to bugs in it");
1232 object[] args = new object [3];
1233 args [0] = object_type;
1234 args [1] = value_type;
1235 args [2] = enum_type;
1237 set_corlib_type_builders.Invoke (CodeGen.Assembly.Builder, args);
1241 system_object_expr.Type = object_type;
1242 system_string_expr.Type = string_type;
1243 system_boolean_expr.Type = bool_type;
1244 system_decimal_expr.Type = decimal_type;
1245 system_single_expr.Type = float_type;
1246 system_double_expr.Type = double_type;
1247 system_sbyte_expr.Type = sbyte_type;
1248 system_byte_expr.Type = byte_type;
1249 system_int16_expr.Type = short_type;
1250 system_uint16_expr.Type = ushort_type;
1251 system_int32_expr.Type = int32_type;
1252 system_uint32_expr.Type = uint32_type;
1253 system_int64_expr.Type = int64_type;
1254 system_uint64_expr.Type = uint64_type;
1255 system_char_expr.Type = char_type;
1256 system_void_expr.Type = void_type;
1257 system_asynccallback_expr.Type = asynccallback_type;
1258 system_iasyncresult_expr.Type = iasyncresult_type;
1259 system_valuetype_expr.Type = value_type;
1263 // The helper methods that are used by the compiler
1265 public static void InitCodeHelpers ()
1268 // Now load the default methods that we use.
1270 Type [] string_string = { string_type, string_type };
1271 string_concat_string_string = GetMethod (
1272 string_type, "Concat", string_string);
1273 Type [] string_string_string = { string_type, string_type, string_type };
1274 string_concat_string_string_string = GetMethod (
1275 string_type, "Concat", string_string_string);
1276 Type [] string_string_string_string = { string_type, string_type, string_type, string_type };
1277 string_concat_string_string_string_string = GetMethod (
1278 string_type, "Concat", string_string_string_string);
1279 Type[] params_string = { TypeManager.LookupType ("System.String[]") };
1280 string_concat_string_dot_dot_dot = GetMethod (
1281 string_type, "Concat", params_string);
1283 Type [] object_object = { object_type, object_type };
1284 string_concat_object_object = GetMethod (
1285 string_type, "Concat", object_object);
1286 Type [] object_object_object = { object_type, object_type, object_type };
1287 string_concat_object_object_object = GetMethod (
1288 string_type, "Concat", object_object_object);
1289 Type[] params_object = { TypeManager.LookupType ("System.Object[]") };
1290 string_concat_object_dot_dot_dot = GetMethod (
1291 string_type, "Concat", params_object);
1293 Type [] string_ = { string_type };
1294 string_isinterneted_string = GetMethod (
1295 string_type, "IsInterned", string_);
1297 Type [] runtime_type_handle = { runtime_handle_type };
1298 system_type_get_type_from_handle = GetMethod (
1299 type_type, "GetTypeFromHandle", runtime_type_handle);
1301 Type [] delegate_delegate = { delegate_type, delegate_type };
1302 delegate_combine_delegate_delegate = GetMethod (
1303 delegate_type, "Combine", delegate_delegate);
1305 delegate_remove_delegate_delegate = GetMethod (
1306 delegate_type, "Remove", delegate_delegate);
1311 Type [] void_arg = { };
1312 object_getcurrent_void = GetMethod (
1313 ienumerator_type, "get_Current", void_arg);
1314 bool_movenext_void = GetMethod (
1315 ienumerator_type, "MoveNext", void_arg);
1316 void_reset_void = GetMethod (
1317 ienumerator_type, "Reset", void_arg);
1318 void_dispose_void = GetMethod (
1319 idisposable_type, "Dispose", void_arg);
1320 int_get_offset_to_string_data = GetMethod (
1321 runtime_helpers_type, "get_OffsetToStringData", void_arg);
1322 int_array_get_length = GetMethod (
1323 array_type, "get_Length", void_arg);
1324 int_array_get_rank = GetMethod (
1325 array_type, "get_Rank", void_arg);
1326 ienumerable_getenumerator_void = GetMethod (
1327 ienumerable_type, "GetEnumerator", void_arg);
1332 Type [] int_arg = { int32_type };
1333 int_array_get_length_int = GetMethod (
1334 array_type, "GetLength", int_arg);
1335 int_array_get_upper_bound_int = GetMethod (
1336 array_type, "GetUpperBound", int_arg);
1337 int_array_get_lower_bound_int = GetMethod (
1338 array_type, "GetLowerBound", int_arg);
1341 // System.Array methods
1343 object_array_clone = GetMethod (
1344 array_type, "Clone", void_arg);
1345 Type [] array_int_arg = { array_type, int32_type };
1346 void_array_copyto_array_int = GetMethod (
1347 array_type, "CopyTo", array_int_arg);
1352 Type [] object_arg = { object_type };
1353 void_monitor_enter_object = GetMethod (
1354 monitor_type, "Enter", object_arg);
1355 void_monitor_exit_object = GetMethod (
1356 monitor_type, "Exit", object_arg);
1358 Type [] array_field_handle_arg = { array_type, runtime_field_handle_type };
1360 void_initializearray_array_fieldhandle = GetMethod (
1361 runtime_helpers_type, "InitializeArray", array_field_handle_arg);
1366 int_getlength_int = GetMethod (
1367 array_type, "GetLength", int_arg);
1370 // Decimal constructors
1372 Type [] dec_arg = { int32_type, int32_type, int32_type, bool_type, byte_type };
1373 void_decimal_ctor_five_args = GetConstructor (
1374 decimal_type, dec_arg);
1379 cons_param_array_attribute = GetConstructor (
1380 param_array_type, void_arg);
1382 unverifiable_code_ctor = GetConstructor (
1383 unverifiable_code_type, void_arg);
1385 default_member_ctor = GetConstructor (default_member_type, string_);
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));
1433 if (t is GenericTypeParameterBuilder) {
1434 TypeParameter tparam = (TypeParameter) builder_to_type_param [t];
1436 Timer.StartTimer (TimerType.FindMembers);
1437 MemberList list = tparam.FindMembers (
1438 mt, bf | BindingFlags.DeclaredOnly, filter, criteria);
1439 Timer.StopTimer (TimerType.FindMembers);
1444 // Since FindMembers will not lookup both static and instance
1445 // members, we emulate this behaviour here.
1447 if ((bf & instance_and_static) == instance_and_static){
1448 MemberInfo [] i_members = t.FindMembers (
1449 mt, bf & ~BindingFlags.Static, filter, criteria);
1451 int i_len = i_members.Length;
1453 MemberInfo one = i_members [0];
1456 // If any of these are present, we are done!
1458 if ((one is Type) || (one is EventInfo) || (one is FieldInfo))
1459 return new MemberList (i_members);
1462 MemberInfo [] s_members = t.FindMembers (
1463 mt, bf & ~BindingFlags.Instance, filter, criteria);
1465 int s_len = s_members.Length;
1466 if (i_len > 0 || s_len > 0)
1467 return new MemberList (i_members, s_members);
1470 return new MemberList (i_members);
1472 return new MemberList (s_members);
1476 return new MemberList (t.FindMembers (mt, bf, filter, criteria));
1481 /// This method is only called from within MemberLookup. It tries to use the member
1482 /// cache if possible and falls back to the normal FindMembers if not. The `used_cache'
1483 /// flag tells the caller whether we used the cache or not. If we used the cache, then
1484 /// our return value will already contain all inherited members and the caller don't need
1485 /// to check base classes and interfaces anymore.
1487 private static MemberInfo [] MemberLookup_FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1488 string name, out bool used_cache)
1491 // We have to take care of arrays specially, because GetType on
1492 // a TypeBuilder array will return a Type, not a TypeBuilder,
1493 // and we can not call FindMembers on this type.
1495 if (t == TypeManager.array_type || t.IsSubclassOf (TypeManager.array_type)) {
1497 return TypeHandle.ArrayType.MemberCache.FindMembers (
1498 mt, bf, name, FilterWithClosure_delegate, null);
1502 // If this is a dynamic type, it's always in the `builder_to_declspace' hash table
1503 // and we can ask the DeclSpace for the MemberCache.
1505 if (t is TypeBuilder) {
1506 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
1507 MemberCache cache = decl.MemberCache;
1510 // If this DeclSpace has a MemberCache, use it.
1513 if (cache != null) {
1515 return cache.FindMembers (
1516 mt, bf, name, FilterWithClosure_delegate, null);
1519 // If there is no MemberCache, we need to use the "normal" FindMembers.
1520 // Note, this is a VERY uncommon route!
1523 Timer.StartTimer (TimerType.FindMembers);
1524 list = decl.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
1525 FilterWithClosure_delegate, name);
1526 Timer.StopTimer (TimerType.FindMembers);
1528 return (MemberInfo []) list;
1531 if (t is GenericTypeParameterBuilder) {
1532 TypeParameter tparam = (TypeParameter) builder_to_type_param [t];
1535 Timer.StartTimer (TimerType.FindMembers);
1536 list = tparam.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
1537 FilterWithClosure_delegate, name);
1538 Timer.StopTimer (TimerType.FindMembers);
1540 return (MemberInfo []) list;
1544 // This call will always succeed. There is exactly one TypeHandle instance per
1545 // type, TypeHandle.GetTypeHandle() will either return it or create a new one
1546 // if it didn't already exist.
1548 TypeHandle handle = TypeHandle.GetTypeHandle (t);
1551 return handle.MemberCache.FindMembers (mt, bf, name, FilterWithClosure_delegate, null);
1554 public static bool IsBuiltinType (Type t)
1556 if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
1557 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1558 t == char_type || t == short_type || t == decimal_type || t == bool_type ||
1559 t == sbyte_type || t == byte_type || t == ushort_type || t == void_type)
1565 public static bool IsBuiltinType (TypeContainer tc)
1567 return IsBuiltinType (tc.TypeBuilder);
1571 // This is like IsBuiltinType, but lacks decimal_type, we should also clean up
1572 // the pieces in the code where we use IsBuiltinType and special case decimal_type.
1574 public static bool IsCLRType (Type t)
1576 if (t == object_type || t == int32_type || t == uint32_type ||
1577 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1578 t == char_type || t == short_type || t == bool_type ||
1579 t == sbyte_type || t == byte_type || t == ushort_type)
1585 public static bool IsDelegateType (Type t)
1587 if (t.IsGenericInstance)
1588 t = t.GetGenericTypeDefinition ();
1590 if (t.IsSubclassOf (TypeManager.delegate_type))
1596 public static bool IsEnumType (Type t)
1598 if (t.IsSubclassOf (TypeManager.enum_type))
1603 public static bool IsBuiltinOrEnum (Type t)
1605 if (IsBuiltinType (t))
1615 // Only a quick hack to get things moving, while real runtime support appears
1617 public static bool IsGeneric (Type t)
1619 DeclSpace ds = (DeclSpace) builder_to_declspace [t];
1621 return ds.IsGeneric;
1624 public static bool HasGenericArguments (Type t)
1626 return GetNumberOfTypeArguments (t) > 0;
1629 public static int GetNumberOfTypeArguments (Type t)
1631 DeclSpace tc = LookupDeclSpace (t);
1633 return tc.IsGeneric ? tc.CountTypeParameters : 0;
1635 return t.HasGenericArguments ? t.GetGenericArguments ().Length : 0;
1638 public static Type[] GetTypeArguments (Type t)
1640 DeclSpace tc = LookupDeclSpace (t);
1643 throw new InvalidOperationException ();
1645 TypeParameter[] tparam = tc.TypeParameters;
1646 Type[] ret = new Type [tparam.Length];
1647 for (int i = 0; i < tparam.Length; i++) {
1648 ret [i] = tparam [i].Type;
1649 if (ret [i] == null)
1650 throw new InternalErrorException ();
1655 return t.GetGenericArguments ();
1659 // Whether a type is unmanaged. This is used by the unsafe code (25.2)
1661 public static bool IsUnmanagedType (Type t)
1663 if (IsBuiltinType (t) && t != TypeManager.string_type)
1672 if (IsValueType (t)){
1673 if (t is TypeBuilder){
1674 TypeContainer tc = LookupTypeContainer (t);
1676 if (tc.Fields != null){
1677 foreach (Field f in tc.Fields){
1678 if (f.FieldBuilder.IsStatic)
1680 if (!IsUnmanagedType (f.FieldBuilder.FieldType))
1686 FieldInfo [] fields = t.GetFields ();
1688 foreach (FieldInfo f in fields){
1691 if (!IsUnmanagedType (f.FieldType))
1701 public static bool IsValueType (Type t)
1703 return t.IsGenericParameter || t.IsValueType;
1706 public static bool IsInterfaceType (Type t)
1708 TypeContainer tc = (TypeContainer) builder_to_declspace [t];
1712 return tc.Kind == Kind.Interface;
1715 public static bool IsEqualGenericType (Type a, Type b)
1717 if ((a is TypeBuilder) && a.IsGenericTypeDefinition && b.IsGenericInstance) {
1719 // `a' is a generic type definition's TypeBuilder and `b' is a
1720 // generic instance of the same type.
1726 // void Test (Stack<T> stack) { }
1729 // The first argument of `Test' will be the generic instance
1730 // "Stack<!0>" - which is the same type than the "Stack" TypeBuilder.
1732 if (a != b.GetGenericTypeDefinition ())
1735 Type[] aparams = a.GetGenericArguments ();
1736 Type[] bparams = b.GetGenericArguments ();
1738 if (aparams.Length != bparams.Length)
1741 for (int i = 0; i < aparams.Length; i++)
1742 if (!aparams [i].Equals (bparams [i]))
1751 public static bool IsEqual (Type a, Type b)
1756 return IsEqualGenericType (a, b);
1759 public static bool MayBecomeEqualGenericTypes (Type a, Type b)
1761 if (a.IsGenericParameter) {
1763 // If a is an array of a's type, they may never
1767 b = b.GetElementType ();
1773 // If b is a generic parameter or an actual type,
1774 // they may become equal:
1776 // class X<T,U> : I<T>, I<U>
1777 // class X<T> : I<T>, I<float>
1779 if (b.IsGenericParameter || !b.IsGenericInstance)
1783 // We're now comparing a type parameter with a
1784 // generic instance. They may become equal unless
1785 // the type parameter appears anywhere in the
1786 // generic instance:
1788 // class X<T,U> : I<T>, I<X<U>>
1789 // -> error because you could instanciate it as
1792 // class X<T> : I<T>, I<X<T>> -> ok
1795 Type[] bargs = GetTypeArguments (b);
1796 for (int i = 0; i < bargs.Length; i++) {
1797 if (a.Equals (bargs [i]))
1804 if (b.IsGenericParameter)
1805 return MayBecomeEqualGenericTypes (b, a);
1808 // At this point, neither a nor b are a type parameter.
1810 // If one of them is a generic instance, let
1811 // MayBecomeEqualGenericInstances() compare them (if the
1812 // other one is not a generic instance, they can never
1816 if (a.IsGenericInstance || b.IsGenericInstance)
1817 return MayBecomeEqualGenericInstances (a, b);
1820 // If both of them are arrays.
1823 if (a.IsArray && b.IsArray) {
1824 if (a.GetArrayRank () != b.GetArrayRank ())
1827 a = a.GetElementType ();
1828 b = b.GetElementType ();
1830 return MayBecomeEqualGenericTypes (a, b);
1834 // Ok, two ordinary types.
1837 return a.Equals (b);
1841 // Checks whether two generic instances may become equal for some
1842 // particular instantiation (26.3.1).
1844 public static bool MayBecomeEqualGenericInstances (Type a, Type b)
1846 if (!a.IsGenericInstance || !b.IsGenericInstance)
1848 if (a.GetGenericTypeDefinition () != b.GetGenericTypeDefinition ())
1851 Type[] aargs = GetTypeArguments (a);
1852 Type[] bargs = GetTypeArguments (b);
1854 if (aargs.Length != bargs.Length)
1857 for (int i = 0; i < aargs.Length; i++) {
1858 if (MayBecomeEqualGenericTypes (aargs [i], bargs [i]))
1865 public static bool IsEqualGenericInstance (Type type, Type parent)
1867 int tcount = GetNumberOfTypeArguments (type);
1868 int pcount = GetNumberOfTypeArguments (parent);
1870 if (type.IsGenericInstance)
1871 type = type.GetGenericTypeDefinition ();
1872 if (parent.IsGenericInstance)
1873 parent = parent.GetGenericTypeDefinition ();
1875 if (tcount != pcount)
1878 return type.Equals (parent);
1881 public static bool IsSubclassOf (Type type, Type parent)
1883 TypeParameter tparam = LookupTypeParameter (type);
1884 TypeParameter pparam = LookupTypeParameter (parent);
1886 if ((tparam != null) && (pparam != null)) {
1887 if (tparam == pparam)
1890 return tparam.IsSubclassOf (parent);
1894 if (type.Equals (parent))
1897 type = type.BaseType;
1898 } while (type != null);
1903 public static bool IsFamilyAccessible (Type type, Type parent)
1905 TypeParameter tparam = LookupTypeParameter (type);
1906 TypeParameter pparam = LookupTypeParameter (parent);
1908 if ((tparam != null) && (pparam != null)) {
1909 if (tparam == pparam)
1912 return tparam.IsSubclassOf (parent);
1916 if (IsEqualGenericInstance (type, parent))
1919 type = type.BaseType;
1920 } while (type != null);
1926 // Checks whether `type' is a subclass or nested child of `parent'.
1928 public static bool IsNestedFamilyAccessible (Type type, Type parent)
1931 if (IsFamilyAccessible (type, parent))
1934 // Handle nested types.
1935 type = type.DeclaringType;
1936 } while (type != null);
1942 // Checks whether `type' is a nested child of `parent'.
1944 public static bool IsNestedChildOf (Type type, Type parent)
1946 if (IsEqual (type, parent))
1949 type = type.DeclaringType;
1950 while (type != null) {
1951 if (IsEqual (type, parent))
1954 type = type.DeclaringType;
1961 // Do the right thing when returning the element type of an
1962 // array type based on whether we are compiling corlib or not
1964 public static Type GetElementType (Type t)
1966 if (RootContext.StdLib)
1967 return t.GetElementType ();
1969 return TypeToCoreType (t.GetElementType ());
1973 /// Returns the User Defined Types
1975 public static ArrayList UserTypes {
1981 public static Hashtable TypeContainers {
1983 return typecontainers;
1987 static Hashtable builder_to_constant;
1989 public static void RegisterConstant (FieldBuilder fb, Const c)
1991 if (builder_to_constant == null)
1992 builder_to_constant = new PtrHashtable ();
1994 if (builder_to_constant.Contains (fb))
1997 builder_to_constant.Add (fb, c);
2000 public static Const LookupConstant (FieldBuilder fb)
2002 if (builder_to_constant == null)
2005 return (Const) builder_to_constant [fb];
2009 /// Gigantic work around for missing features in System.Reflection.Emit follows.
2013 /// Since System.Reflection.Emit can not return MethodBase.GetParameters
2014 /// for anything which is dynamic, and we need this in a number of places,
2015 /// we register this information here, and use it afterwards.
2017 static public void RegisterMethod (MethodBase mb, InternalParameters ip, Type [] args)
2022 method_arguments.Add (mb, args);
2023 method_internal_params.Add (mb, ip);
2026 static public InternalParameters LookupParametersByBuilder (MethodBase mb)
2028 if (! (mb is ConstructorBuilder || mb is MethodBuilder))
2031 if (method_internal_params.Contains (mb))
2032 return (InternalParameters) method_internal_params [mb];
2034 throw new Exception ("Argument for Method not registered" + mb);
2038 /// Returns the argument types for a method based on its methodbase
2040 /// For dynamic methods, we use the compiler provided types, for
2041 /// methods from existing assemblies we load them from GetParameters,
2042 /// and insert them into the cache
2044 static public Type [] GetArgumentTypes (MethodBase mb)
2046 object t = method_arguments [mb];
2050 ParameterInfo [] pi = mb.GetParameters ();
2057 types = new Type [c];
2058 for (int i = 0; i < c; i++)
2059 types [i] = pi [i].ParameterType;
2061 method_arguments.Add (mb, types);
2066 /// Returns the argument types for an indexer based on its PropertyInfo
2068 /// For dynamic indexers, we use the compiler provided types, for
2069 /// indexers from existing assemblies we load them from GetParameters,
2070 /// and insert them into the cache
2072 static public Type [] GetArgumentTypes (PropertyInfo indexer)
2074 if (indexer_arguments.Contains (indexer))
2075 return (Type []) indexer_arguments [indexer];
2076 else if (indexer is PropertyBuilder)
2077 // If we're a PropertyBuilder and not in the
2078 // `indexer_arguments' hash, then we're a property and
2082 ParameterInfo [] pi = indexer.GetIndexParameters ();
2083 // Property, not an indexer.
2087 Type [] types = new Type [c];
2089 for (int i = 0; i < c; i++)
2090 types [i] = pi [i].ParameterType;
2092 indexer_arguments.Add (indexer, types);
2098 // This is a workaround the fact that GetValue is not
2099 // supported for dynamic types
2101 static Hashtable fields = new Hashtable ();
2102 static public bool RegisterFieldValue (FieldBuilder fb, object value)
2104 if (fields.Contains (fb))
2107 fields.Add (fb, value);
2112 static public object GetValue (FieldBuilder fb)
2117 static Hashtable fieldbuilders_to_fields = new Hashtable ();
2118 static public bool RegisterFieldBase (FieldBuilder fb, FieldBase f)
2120 if (fieldbuilders_to_fields.Contains (fb))
2123 fieldbuilders_to_fields.Add (fb, f);
2128 // The return value can be null; This will be the case for
2129 // auxiliary FieldBuilders created by the compiler that have no
2130 // real field being declared on the source code
2132 static public FieldBase GetField (FieldInfo fb)
2134 return (FieldBase) fieldbuilders_to_fields [fb];
2137 static Hashtable events;
2139 static public void RegisterEvent (MyEventBuilder eb, MethodBase add, MethodBase remove)
2142 events = new Hashtable ();
2144 if (!events.Contains (eb)) {
2145 events.Add (eb, new Pair (add, remove));
2149 static public MethodInfo GetAddMethod (EventInfo ei)
2151 if (ei is MyEventBuilder) {
2152 Pair pair = (Pair) events [ei];
2154 return (MethodInfo) pair.First;
2156 return ei.GetAddMethod (true);
2159 static public MethodInfo GetRemoveMethod (EventInfo ei)
2161 if (ei is MyEventBuilder) {
2162 Pair pair = (Pair) events [ei];
2164 return (MethodInfo) pair.Second;
2166 return ei.GetRemoveMethod (true);
2169 static Hashtable priv_fields_events;
2171 static public bool RegisterPrivateFieldOfEvent (EventInfo einfo, FieldBuilder builder)
2173 if (priv_fields_events == null)
2174 priv_fields_events = new Hashtable ();
2176 if (priv_fields_events.Contains (einfo))
2179 priv_fields_events.Add (einfo, builder);
2184 static public MemberInfo GetPrivateFieldOfEvent (EventInfo ei)
2186 if (priv_fields_events == null)
2189 return (MemberInfo) priv_fields_events [ei];
2192 static Hashtable properties;
2194 static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set)
2196 if (properties == null)
2197 properties = new Hashtable ();
2199 if (properties.Contains (pb))
2202 properties.Add (pb, new Pair (get, set));
2207 static public bool RegisterIndexer (PropertyBuilder pb, MethodBase get,
2208 MethodBase set, Type[] args)
2210 if (!RegisterProperty (pb, get,set))
2213 indexer_arguments.Add (pb, args);
2218 public static bool CheckStructCycles (TypeContainer tc, Hashtable seen)
2220 Hashtable hash = new Hashtable ();
2221 return CheckStructCycles (tc, seen, hash);
2224 public static bool CheckStructCycles (TypeContainer tc, Hashtable seen,
2227 if ((tc.Kind != Kind.Struct) || IsBuiltinType (tc))
2231 // `seen' contains all types we've already visited.
2233 if (seen.Contains (tc))
2235 seen.Add (tc, null);
2237 if (tc.Fields == null)
2240 foreach (Field field in tc.Fields) {
2241 if (field.FieldBuilder.IsStatic)
2244 Type ftype = field.FieldBuilder.FieldType;
2245 TypeContainer ftc = LookupTypeContainer (ftype);
2249 if (hash.Contains (ftc)) {
2250 Report.Error (523, tc.Location,
2251 "Struct member `{0}.{1}' of type `{2}' " +
2252 "causes a cycle in the struct layout",
2253 tc.Name, field.Name, ftc.Name);
2258 // `hash' contains all types in the current path.
2260 hash.Add (tc, null);
2262 bool ok = CheckStructCycles (ftc, seen, hash);
2269 if (!seen.Contains (ftc))
2270 seen.Add (ftc, null);
2277 /// Given an array of interface types, expand and eliminate repeated ocurrences
2278 /// of an interface.
2282 /// This expands in context like: IA; IB : IA; IC : IA, IB; the interface "IC" to
2285 public static Type[] ExpandInterfaces (EmitContext ec, TypeExpr [] base_interfaces)
2287 ArrayList new_ifaces = new ArrayList ();
2289 foreach (TypeExpr iface in base_interfaces){
2290 Type itype = iface.ResolveType (ec);
2294 if (!new_ifaces.Contains (itype))
2295 new_ifaces.Add (itype);
2297 Type [] implementing = itype.GetInterfaces ();
2299 foreach (Type imp in implementing){
2300 if (!new_ifaces.Contains (imp))
2301 new_ifaces.Add (imp);
2304 Type [] ret = new Type [new_ifaces.Count];
2305 new_ifaces.CopyTo (ret, 0);
2309 static PtrHashtable iface_cache = new PtrHashtable ();
2312 /// This function returns the interfaces in the type `t'. Works with
2313 /// both types and TypeBuilders.
2315 public static Type [] GetInterfaces (Type t)
2318 Type [] cached = iface_cache [t] as Type [];
2323 // The reason for catching the Array case is that Reflection.Emit
2324 // will not return a TypeBuilder for Array types of TypeBuilder types,
2325 // but will still throw an exception if we try to call GetInterfaces
2328 // Since the array interfaces are always constant, we return those for
2333 t = TypeManager.array_type;
2335 if (t is TypeBuilder){
2336 Type[] parent_ifaces;
2338 if (t.BaseType == null)
2339 parent_ifaces = NoTypes;
2341 parent_ifaces = GetInterfaces (t.BaseType);
2342 Type[] type_ifaces = (Type []) builder_to_ifaces [t];
2343 if (type_ifaces == null)
2344 type_ifaces = NoTypes;
2346 int parent_count = parent_ifaces.Length;
2347 Type[] result = new Type [parent_count + type_ifaces.Length];
2348 parent_ifaces.CopyTo (result, 0);
2349 type_ifaces.CopyTo (result, parent_count);
2351 iface_cache [t] = result;
2353 } else if (t is GenericTypeParameterBuilder){
2354 Type[] type_ifaces = (Type []) builder_to_ifaces [t];
2355 if (type_ifaces == null)
2356 type_ifaces = NoTypes;
2358 iface_cache [t] = type_ifaces;
2361 Type[] ifaces = t.GetInterfaces ();
2362 iface_cache [t] = ifaces;
2368 // gets the interfaces that are declared explicitly on t
2370 public static Type [] GetExplicitInterfaces (TypeBuilder t)
2372 return (Type []) builder_to_ifaces [t];
2376 /// The following is used to check if a given type implements an interface.
2377 /// The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
2379 public static bool ImplementsInterface (Type t, Type iface)
2384 // FIXME OPTIMIZATION:
2385 // as soon as we hit a non-TypeBuiler in the interface
2386 // chain, we could return, as the `Type.GetInterfaces'
2387 // will return all the interfaces implement by the type
2391 interfaces = GetInterfaces (t);
2393 if (interfaces != null){
2394 foreach (Type i in interfaces){
2401 } while (t != null);
2406 static NumberFormatInfo nf_provider = CultureInfo.CurrentCulture.NumberFormat;
2408 // This is a custom version of Convert.ChangeType() which works
2409 // with the TypeBuilder defined types when compiling corlib.
2410 public static object ChangeType (object value, Type conversionType, out bool error)
2412 IConvertible convert_value = value as IConvertible;
2414 if (convert_value == null){
2420 // We must use Type.Equals() here since `conversionType' is
2421 // the TypeBuilder created version of a system type and not
2422 // the system type itself. You cannot use Type.GetTypeCode()
2423 // on such a type - it'd always return TypeCode.Object.
2427 if (conversionType.Equals (typeof (Boolean)))
2428 return (object)(convert_value.ToBoolean (nf_provider));
2429 else if (conversionType.Equals (typeof (Byte)))
2430 return (object)(convert_value.ToByte (nf_provider));
2431 else if (conversionType.Equals (typeof (Char)))
2432 return (object)(convert_value.ToChar (nf_provider));
2433 else if (conversionType.Equals (typeof (DateTime)))
2434 return (object)(convert_value.ToDateTime (nf_provider));
2435 else if (conversionType.Equals (typeof (Decimal)))
2436 return (object)(convert_value.ToDecimal (nf_provider));
2437 else if (conversionType.Equals (typeof (Double)))
2438 return (object)(convert_value.ToDouble (nf_provider));
2439 else if (conversionType.Equals (typeof (Int16)))
2440 return (object)(convert_value.ToInt16 (nf_provider));
2441 else if (conversionType.Equals (typeof (Int32)))
2442 return (object)(convert_value.ToInt32 (nf_provider));
2443 else if (conversionType.Equals (typeof (Int64)))
2444 return (object)(convert_value.ToInt64 (nf_provider));
2445 else if (conversionType.Equals (typeof (SByte)))
2446 return (object)(convert_value.ToSByte (nf_provider));
2447 else if (conversionType.Equals (typeof (Single)))
2448 return (object)(convert_value.ToSingle (nf_provider));
2449 else if (conversionType.Equals (typeof (String)))
2450 return (object)(convert_value.ToString (nf_provider));
2451 else if (conversionType.Equals (typeof (UInt16)))
2452 return (object)(convert_value.ToUInt16 (nf_provider));
2453 else if (conversionType.Equals (typeof (UInt32)))
2454 return (object)(convert_value.ToUInt32 (nf_provider));
2455 else if (conversionType.Equals (typeof (UInt64)))
2456 return (object)(convert_value.ToUInt64 (nf_provider));
2457 else if (conversionType.Equals (typeof (Object)))
2458 return (object)(value);
2468 // This is needed, because enumerations from assemblies
2469 // do not report their underlyingtype, but they report
2472 public static Type EnumToUnderlying (Type t)
2474 if (t == TypeManager.enum_type)
2477 t = t.UnderlyingSystemType;
2478 if (!TypeManager.IsEnumType (t))
2481 if (t is TypeBuilder) {
2482 // slow path needed to compile corlib
2483 if (t == TypeManager.bool_type ||
2484 t == TypeManager.byte_type ||
2485 t == TypeManager.sbyte_type ||
2486 t == TypeManager.char_type ||
2487 t == TypeManager.short_type ||
2488 t == TypeManager.ushort_type ||
2489 t == TypeManager.int32_type ||
2490 t == TypeManager.uint32_type ||
2491 t == TypeManager.int64_type ||
2492 t == TypeManager.uint64_type)
2494 throw new Exception ("Unhandled typecode in enum " + " from " + t.AssemblyQualifiedName);
2496 TypeCode tc = Type.GetTypeCode (t);
2499 case TypeCode.Boolean:
2500 return TypeManager.bool_type;
2502 return TypeManager.byte_type;
2503 case TypeCode.SByte:
2504 return TypeManager.sbyte_type;
2506 return TypeManager.char_type;
2507 case TypeCode.Int16:
2508 return TypeManager.short_type;
2509 case TypeCode.UInt16:
2510 return TypeManager.ushort_type;
2511 case TypeCode.Int32:
2512 return TypeManager.int32_type;
2513 case TypeCode.UInt32:
2514 return TypeManager.uint32_type;
2515 case TypeCode.Int64:
2516 return TypeManager.int64_type;
2517 case TypeCode.UInt64:
2518 return TypeManager.uint64_type;
2520 throw new Exception ("Unhandled typecode in enum " + tc + " from " + t.AssemblyQualifiedName);
2524 // When compiling corlib and called with one of the core types, return
2525 // the corresponding typebuilder for that type.
2527 public static Type TypeToCoreType (Type t)
2529 if (RootContext.StdLib || (t is TypeBuilder))
2532 TypeCode tc = Type.GetTypeCode (t);
2535 case TypeCode.Boolean:
2536 return TypeManager.bool_type;
2538 return TypeManager.byte_type;
2539 case TypeCode.SByte:
2540 return TypeManager.sbyte_type;
2542 return TypeManager.char_type;
2543 case TypeCode.Int16:
2544 return TypeManager.short_type;
2545 case TypeCode.UInt16:
2546 return TypeManager.ushort_type;
2547 case TypeCode.Int32:
2548 return TypeManager.int32_type;
2549 case TypeCode.UInt32:
2550 return TypeManager.uint32_type;
2551 case TypeCode.Int64:
2552 return TypeManager.int64_type;
2553 case TypeCode.UInt64:
2554 return TypeManager.uint64_type;
2555 case TypeCode.Single:
2556 return TypeManager.float_type;
2557 case TypeCode.Double:
2558 return TypeManager.double_type;
2559 case TypeCode.String:
2560 return TypeManager.string_type;
2562 if (t == typeof (void))
2563 return TypeManager.void_type;
2564 if (t == typeof (object))
2565 return TypeManager.object_type;
2566 if (t == typeof (System.Type))
2567 return TypeManager.type_type;
2568 if (t == typeof (System.IntPtr))
2569 return TypeManager.intptr_type;
2575 /// Utility function that can be used to probe whether a type
2576 /// is managed or not.
2578 public static bool VerifyUnManaged (Type t, Location loc)
2580 if (t.IsValueType || t.IsPointer){
2582 // FIXME: this is more complex, we actually need to
2583 // make sure that the type does not contain any
2589 if (!RootContext.StdLib && (t == TypeManager.decimal_type))
2590 // We need this explicit check here to make it work when
2591 // compiling corlib.
2596 "Cannot take the address or size of a variable of a managed type ('" +
2597 CSharpName (t) + "')");
2602 /// Returns the name of the indexer in a given type.
2605 /// The default is not always `Item'. The user can change this behaviour by
2606 /// using the IndexerNameAttribute in the container.
2608 /// For example, the String class indexer is named `Chars' not `Item'
2610 public static string IndexerPropertyName (Type t)
2612 if (t.IsGenericInstance)
2613 t = t.GetGenericTypeDefinition ();
2615 if (t is TypeBuilder) {
2616 TypeContainer tc = t.IsInterface ? LookupInterface (t) : LookupTypeContainer (t);
2617 return tc == null ? TypeContainer.DefaultIndexerName : tc.IndexerName;
2620 System.Attribute attr = System.Attribute.GetCustomAttribute (
2621 t, TypeManager.default_member_type);
2623 DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
2624 return dma.MemberName;
2627 return TypeContainer.DefaultIndexerName;
2630 static MethodInfo declare_local_method = null;
2632 public static LocalBuilder DeclareLocalPinned (ILGenerator ig, Type t)
2634 if (declare_local_method == null){
2635 declare_local_method = typeof (ILGenerator).GetMethod (
2637 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
2639 new Type [] { typeof (Type), typeof (bool)},
2641 if (declare_local_method == null){
2642 Report.Warning (-24, new Location (-1),
2643 "This version of the runtime does not support making pinned local variables. " +
2644 "This code may cause errors on a runtime with a moving GC");
2645 return ig.DeclareLocal (t);
2648 return (LocalBuilder) declare_local_method.Invoke (ig, new object [] { t, true });
2652 // Returns whether the array of memberinfos contains the given method
2654 public static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method)
2656 Type [] new_args = TypeManager.GetArgumentTypes (new_method);
2658 foreach (MethodBase method in array) {
2659 if (method.Name != new_method.Name)
2662 if (method is MethodInfo && new_method is MethodInfo)
2663 if (((MethodInfo) method).ReturnType != ((MethodInfo) new_method).ReturnType)
2667 Type [] old_args = TypeManager.GetArgumentTypes (method);
2668 int old_count = old_args.Length;
2671 if (new_args.Length != old_count)
2674 for (i = 0; i < old_count; i++){
2675 if (old_args [i] != new_args [i])
2688 // We copy methods from `new_members' into `target_list' if the signature
2689 // for the method from in the new list does not exist in the target_list
2691 // The name is assumed to be the same.
2693 public static ArrayList CopyNewMethods (ArrayList target_list, IList new_members)
2695 if (target_list == null){
2696 target_list = new ArrayList ();
2698 foreach (MemberInfo mi in new_members){
2699 if (mi is MethodBase)
2700 target_list.Add (mi);
2705 MemberInfo [] target_array = new MemberInfo [target_list.Count];
2706 target_list.CopyTo (target_array, 0);
2708 foreach (MemberInfo mi in new_members){
2709 MethodBase new_method = (MethodBase) mi;
2711 if (!ArrayContainsMethod (target_array, new_method))
2712 target_list.Add (new_method);
2717 static public bool IsGenericMethod (MethodBase mb)
2719 if (mb.DeclaringType is TypeBuilder) {
2720 IMethodData method = (IMethodData) builder_to_method [mb];
2724 return method.GenericMethod != null;
2727 return mb.IsGenericMethodDefinition;
2730 #region MemberLookup implementation
2733 // Whether we allow private members in the result (since FindMembers
2734 // uses NonPublic for both protected and private), we need to distinguish.
2737 static internal bool FilterNone (MemberInfo m, object filter_criteria)
2742 internal class Closure {
2743 internal bool private_ok;
2745 // Who is invoking us and which type is being queried currently.
2746 internal Type invocation_type;
2747 internal Type qualifier_type;
2749 // The assembly that defines the type is that is calling us
2750 internal Assembly invocation_assembly;
2751 internal IList almost_match;
2753 private bool CheckValidFamilyAccess (bool is_static, MemberInfo m)
2755 if (invocation_type == null)
2761 // A nested class has access to all the protected members visible
2763 if (qualifier_type != null
2764 && TypeManager.IsNestedChildOf (invocation_type, qualifier_type))
2767 if (invocation_type == m.DeclaringType
2768 || invocation_type.IsSubclassOf (m.DeclaringType)) {
2769 // Although a derived class can access protected members of
2770 // its base class it cannot do so through an instance of the
2771 // base class (CS1540).
2772 // => Ancestry should be: declaring_type ->* invocation_type
2773 // ->* qualified_type
2774 if (qualifier_type == null
2775 || qualifier_type == invocation_type
2776 || qualifier_type.IsSubclassOf (invocation_type))
2780 if (almost_match != null)
2781 almost_match.Add (m);
2785 bool Filter (MethodBase mb, object filter_criteria)
2787 MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
2789 if (ma == MethodAttributes.Private)
2790 return private_ok ||
2791 IsEqual (invocation_type, mb.DeclaringType) ||
2792 IsNestedChildOf (invocation_type, mb.DeclaringType);
2795 // FamAndAssem requires that we not only derivate, but we are on the
2798 if (ma == MethodAttributes.FamANDAssem){
2799 if (invocation_assembly != mb.DeclaringType.Assembly)
2803 // Assembly and FamORAssem succeed if we're in the same assembly.
2804 if ((ma == MethodAttributes.Assembly) || (ma == MethodAttributes.FamORAssem)){
2805 if (invocation_assembly == mb.DeclaringType.Assembly)
2809 // We already know that we aren't in the same assembly.
2810 if (ma == MethodAttributes.Assembly)
2813 // Family and FamANDAssem require that we derive.
2814 if ((ma == MethodAttributes.Family) || (ma == MethodAttributes.FamANDAssem)){
2815 if (invocation_type == null)
2818 if (!IsNestedFamilyAccessible (invocation_type, mb.DeclaringType))
2821 // Although a derived class can access protected members of its base class
2822 // it cannot do so through an instance of the base class (CS1540).
2823 if (!mb.IsStatic && (qualifier_type != null) &&
2824 !IsEqualGenericInstance (invocation_type, qualifier_type) &&
2825 TypeManager.IsFamilyAccessible (invocation_type, qualifier_type) &&
2826 !TypeManager.IsNestedChildOf (invocation_type, qualifier_type))
2836 bool Filter (FieldInfo fi, object filter_criteria)
2838 FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask;
2840 if (fa == FieldAttributes.Private)
2841 return private_ok ||
2842 IsEqual (invocation_type, fi.DeclaringType) ||
2843 IsNestedChildOf (invocation_type, fi.DeclaringType);
2846 // FamAndAssem requires that we not only derivate, but we are on the
2849 if (fa == FieldAttributes.FamANDAssem){
2850 if (invocation_assembly != fi.DeclaringType.Assembly)
2854 // Assembly and FamORAssem succeed if we're in the same assembly.
2855 if ((fa == FieldAttributes.Assembly) || (fa == FieldAttributes.FamORAssem)){
2856 if (invocation_assembly == fi.DeclaringType.Assembly)
2860 // We already know that we aren't in the same assembly.
2861 if (fa == FieldAttributes.Assembly)
2864 // Family and FamANDAssem require that we derive.
2865 if ((fa == FieldAttributes.Family) || (fa == FieldAttributes.FamANDAssem)){
2866 if (invocation_type == null)
2869 if (!IsNestedFamilyAccessible (invocation_type, fi.DeclaringType))
2872 // Although a derived class can access protected members of its base class
2873 // it cannot do so through an instance of the base class (CS1540).
2874 if (!fi.IsStatic && (qualifier_type != null) &&
2875 !IsEqualGenericInstance (invocation_type, qualifier_type) &&
2876 TypeManager.IsFamilyAccessible (invocation_type, qualifier_type) &&
2877 !TypeManager.IsNestedChildOf (invocation_type, qualifier_type))
2888 // This filter filters by name + whether it is ok to include private
2889 // members in the search
2891 internal bool Filter (MemberInfo m, object filter_criteria)
2894 // Hack: we know that the filter criteria will always be in the
2895 // `closure' // fields.
2898 if ((filter_criteria != null) && (m.Name != (string) filter_criteria))
2901 if (((qualifier_type == null) || (qualifier_type == invocation_type)) &&
2902 (invocation_type != null) &&
2903 IsEqual (m.DeclaringType, invocation_type))
2907 // Ugly: we need to find out the type of `m', and depending
2908 // on this, tell whether we accept or not
2910 if (m is MethodBase)
2911 return Filter ((MethodBase) m, filter_criteria);
2914 return Filter ((FieldInfo) m, filter_criteria);
2917 // EventInfos and PropertyInfos, return true because they lack
2918 // permission information, so we need to check later on the methods.
2924 static Closure closure = new Closure ();
2925 static MemberFilter FilterWithClosure_delegate = new MemberFilter (closure.Filter);
2928 // Looks up a member called `name' in the `queried_type'. This lookup
2929 // is done by code that is contained in the definition for `invocation_type'
2930 // through a qualifier of type `qualifier_type' (or null if there is no qualifier).
2932 // `invocation_type' is used to check whether we're allowed to access the requested
2933 // member wrt its protection level.
2935 // When called from MemberAccess, `qualifier_type' is the type which is used to access
2936 // the requested member (`class B { A a = new A (); a.foo = 5; }'; here invocation_type
2937 // is B and qualifier_type is A). This is used to do the CS1540 check.
2939 // When resolving a SimpleName, `qualifier_type' is null.
2941 // The `qualifier_type' is used for the CS1540 check; it's normally either null or
2942 // the same than `queried_type' - except when we're being called from BaseAccess;
2943 // in this case, `invocation_type' is the current type and `queried_type' the base
2944 // type, so this'd normally trigger a CS1540.
2946 // The binding flags are `bf' and the kind of members being looked up are `mt'
2948 // The return value always includes private members which code in `invocation_type'
2949 // is allowed to access (using the specified `qualifier_type' if given); only use
2950 // BindingFlags.NonPublic to bypass the permission check.
2952 // The 'almost_match' argument is used for reporting error CS1540.
2954 // Returns an array of a single element for everything but Methods/Constructors
2955 // that might return multiple matches.
2957 public static MemberInfo [] MemberLookup (Type invocation_type, Type qualifier_type,
2958 Type queried_type, MemberTypes mt,
2959 BindingFlags original_bf, string name, IList almost_match)
2961 Timer.StartTimer (TimerType.MemberLookup);
2963 MemberInfo[] retval = RealMemberLookup (invocation_type, qualifier_type,
2964 queried_type, mt, original_bf, name, almost_match);
2966 Timer.StopTimer (TimerType.MemberLookup);
2971 static MemberInfo [] RealMemberLookup (Type invocation_type, Type qualifier_type,
2972 Type queried_type, MemberTypes mt,
2973 BindingFlags original_bf, string name, IList almost_match)
2975 BindingFlags bf = original_bf;
2977 ArrayList method_list = null;
2978 Type current_type = queried_type;
2979 bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0;
2980 bool skip_iface_check = true, used_cache = false;
2981 bool always_ok_flag = false;
2983 closure.invocation_type = invocation_type;
2984 closure.invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
2985 closure.qualifier_type = qualifier_type;
2986 closure.almost_match = almost_match;
2989 // If we are a nested class, we always have access to our container
2992 if (invocation_type != null){
2993 string invocation_name = invocation_type.FullName;
2994 if ((invocation_name != null) && (invocation_name.IndexOf ('+') != -1)){
2995 string container = queried_type.FullName + "+";
2996 int container_length = container.Length;
2998 if (invocation_name.Length > container_length){
2999 string shared = invocation_name.Substring (0, container_length);
3001 if (shared == container)
3002 always_ok_flag = true;
3007 // This is from the first time we find a method
3008 // in most cases, we do not actually find a method in the base class
3009 // so we can just ignore it, and save the arraylist allocation
3010 MemberInfo [] first_members_list = null;
3011 bool use_first_members_list = false;
3017 // `NonPublic' is lame, because it includes both protected and
3018 // private methods, so we need to control this behavior by
3019 // explicitly tracking if a private method is ok or not.
3021 // The possible cases are:
3022 // public, private and protected (internal does not come into the
3025 if ((invocation_type != null) &&
3026 ((invocation_type == current_type) ||
3027 IsNestedChildOf (invocation_type, current_type)) ||
3029 bf = original_bf | BindingFlags.NonPublic;
3033 closure.private_ok = (original_bf & BindingFlags.NonPublic) != 0;
3035 Timer.StopTimer (TimerType.MemberLookup);
3037 list = MemberLookup_FindMembers (
3038 current_type, mt, bf, name, out used_cache);
3040 Timer.StartTimer (TimerType.MemberLookup);
3043 // When queried for an interface type, the cache will automatically check all
3044 // inherited members, so we don't need to do this here. However, this only
3045 // works if we already used the cache in the first iteration of this loop.
3047 // If we used the cache in any further iteration, we can still terminate the
3048 // loop since the cache always looks in all parent classes.
3054 skip_iface_check = false;
3056 if (current_type == TypeManager.object_type)
3059 current_type = current_type.BaseType;
3062 // This happens with interfaces, they have a null
3063 // basetype. Look members up in the Object class.
3065 if (current_type == null)
3066 current_type = TypeManager.object_type;
3069 if (list.Length == 0)
3073 // Events and types are returned by both `static' and `instance'
3074 // searches, which means that our above FindMembers will
3075 // return two copies of the same.
3077 if (list.Length == 1 && !(list [0] is MethodBase)){
3082 // Multiple properties: we query those just to find out the indexer
3085 if (list [0] is PropertyInfo)
3089 // We found an event: the cache lookup returns both the event and
3090 // its private field.
3092 if (list [0] is EventInfo) {
3093 if ((list.Length == 2) && (list [1] is FieldInfo))
3094 return new MemberInfo [] { list [0] };
3101 // We found methods, turn the search into "method scan"
3105 if (first_members_list != null) {
3106 if (use_first_members_list) {
3107 method_list = CopyNewMethods (method_list, first_members_list);
3108 use_first_members_list = false;
3111 method_list = CopyNewMethods (method_list, list);
3113 first_members_list = list;
3114 use_first_members_list = true;
3116 mt &= (MemberTypes.Method | MemberTypes.Constructor);
3118 } while (searching);
3120 if (use_first_members_list) {
3121 foreach (MemberInfo mi in first_members_list) {
3122 if (! (mi is MethodBase)) {
3123 method_list = CopyNewMethods (method_list, first_members_list);
3124 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
3127 return (MemberInfo []) first_members_list;
3130 if (method_list != null && method_list.Count > 0) {
3131 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
3134 // This happens if we already used the cache in the first iteration, in this case
3135 // the cache already looked in all interfaces.
3137 if (skip_iface_check)
3141 // Interfaces do not list members they inherit, so we have to
3144 if (!queried_type.IsInterface)
3147 if (queried_type.IsArray)
3148 queried_type = TypeManager.array_type;
3150 Type [] ifaces = GetInterfaces (queried_type);
3154 foreach (Type itype in ifaces){
3157 x = MemberLookup (null, null, itype, mt, bf, name, null);
3165 // Tests whether external method is really special
3166 public static bool IsSpecialMethod (MethodBase mb)
3168 string name = mb.Name;
3169 if (name.StartsWith ("get_") || name.StartsWith ("set_"))
3170 return mb.DeclaringType.GetProperty (name.Substring (4)) != null;
3172 if (name.StartsWith ("add_"))
3173 return mb.DeclaringType.GetEvent (name.Substring (4)) != null;
3175 if (name.StartsWith ("remove_"))
3176 return mb.DeclaringType.GetEvent (name.Substring (7)) != null;
3178 if (name.StartsWith ("op_")){
3179 foreach (string oname in Unary.oper_names) {
3184 foreach (string oname in Binary.oper_names) {
3197 /// There is exactly one instance of this class per type.
3199 public sealed class TypeHandle : IMemberContainer {
3200 public readonly TypeHandle BaseType;
3202 readonly int id = ++next_id;
3203 static int next_id = 0;
3206 /// Lookup a TypeHandle instance for the given type. If the type doesn't have
3207 /// a TypeHandle yet, a new instance of it is created. This static method
3208 /// ensures that we'll only have one TypeHandle instance per type.
3210 public static TypeHandle GetTypeHandle (Type t)
3212 TypeHandle handle = (TypeHandle) type_hash [t];
3216 handle = new TypeHandle (t);
3217 type_hash.Add (t, handle);
3221 public static void CleanUp ()
3227 /// Returns the TypeHandle for TypeManager.object_type.
3229 public static IMemberContainer ObjectType {
3231 if (object_type != null)
3234 object_type = GetTypeHandle (TypeManager.object_type);
3241 /// Returns the TypeHandle for TypeManager.array_type.
3243 public static IMemberContainer ArrayType {
3245 if (array_type != null)
3248 array_type = GetTypeHandle (TypeManager.array_type);
3254 private static PtrHashtable type_hash = new PtrHashtable ();
3256 private static TypeHandle object_type = null;
3257 private static TypeHandle array_type = null;
3260 private string full_name;
3261 private bool is_interface;
3262 private MemberCache member_cache;
3264 private TypeHandle (Type type)
3267 full_name = type.FullName != null ? type.FullName : type.Name;
3268 if (type.BaseType != null)
3269 BaseType = GetTypeHandle (type.BaseType);
3270 this.is_interface = type.IsInterface || type.IsGenericParameter;
3271 this.member_cache = new MemberCache (this);
3274 // IMemberContainer methods
3276 public string Name {
3288 public IMemberContainer ParentContainer {
3294 public bool IsInterface {
3296 return is_interface;
3300 public MemberList GetMembers (MemberTypes mt, BindingFlags bf)
3302 MemberInfo [] members;
3303 if (type is GenericTypeParameterBuilder)
3304 return MemberList.Empty;
3305 if (mt == MemberTypes.Event)
3306 members = type.GetEvents (bf | BindingFlags.DeclaredOnly);
3308 members = type.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
3310 Array.Reverse (members);
3312 return new MemberList (members);
3315 // IMemberFinder methods
3317 public MemberList FindMembers (MemberTypes mt, BindingFlags bf, string name,
3318 MemberFilter filter, object criteria)
3320 return new MemberList (member_cache.FindMembers (mt, bf, name, filter, criteria));
3323 public MemberCache MemberCache {
3325 return member_cache;
3329 public override string ToString ()
3331 if (BaseType != null)
3332 return "TypeHandle (" + id + "," + Name + " : " + BaseType + ")";
3334 return "TypeHandle (" + id + "," + Name + ")";