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)" +
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)
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));
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 IndexerNameAttribute in the container.
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 TypeContainer tc = t.IsInterface ? LookupInterface (t) : LookupTypeContainer (t);
2580 return tc == null ? TypeContainer.DefaultIndexerName : tc.IndexerName;
2583 System.Attribute attr = System.Attribute.GetCustomAttribute (
2584 t, TypeManager.default_member_type);
2586 DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
2587 return dma.MemberName;
2590 return TypeContainer.DefaultIndexerName;
2593 static MethodInfo declare_local_method = null;
2595 public static LocalBuilder DeclareLocalPinned (ILGenerator ig, Type t)
2597 if (declare_local_method == null){
2598 declare_local_method = typeof (ILGenerator).GetMethod (
2600 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
2602 new Type [] { typeof (Type), typeof (bool)},
2604 if (declare_local_method == null){
2605 Report.Warning (-24, new Location (-1),
2606 "This version of the runtime does not support making pinned local variables. " +
2607 "This code may cause errors on a runtime with a moving GC");
2608 return ig.DeclareLocal (t);
2611 return (LocalBuilder) declare_local_method.Invoke (ig, new object [] { t, true });
2615 // Returns whether the array of memberinfos contains the given method
2617 public static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method)
2619 Type [] new_args = TypeManager.GetArgumentTypes (new_method);
2621 foreach (MethodBase method in array) {
2622 if (method.Name != new_method.Name)
2625 if (method is MethodInfo && new_method is MethodInfo)
2626 if (((MethodInfo) method).ReturnType != ((MethodInfo) new_method).ReturnType)
2630 Type [] old_args = TypeManager.GetArgumentTypes (method);
2631 int old_count = old_args.Length;
2634 if (new_args.Length != old_count)
2637 for (i = 0; i < old_count; i++){
2638 if (old_args [i] != new_args [i])
2651 // We copy methods from `new_members' into `target_list' if the signature
2652 // for the method from in the new list does not exist in the target_list
2654 // The name is assumed to be the same.
2656 public static ArrayList CopyNewMethods (ArrayList target_list, IList new_members)
2658 if (target_list == null){
2659 target_list = new ArrayList ();
2661 foreach (MemberInfo mi in new_members){
2662 if (mi is MethodBase)
2663 target_list.Add (mi);
2668 MemberInfo [] target_array = new MemberInfo [target_list.Count];
2669 target_list.CopyTo (target_array, 0);
2671 foreach (MemberInfo mi in new_members){
2672 MethodBase new_method = (MethodBase) mi;
2674 if (!ArrayContainsMethod (target_array, new_method))
2675 target_list.Add (new_method);
2680 static public bool IsGenericMethod (MethodBase mb)
2682 if (mb.DeclaringType is TypeBuilder) {
2683 IMethodData method = (IMethodData) builder_to_method [mb];
2687 return method.GenericMethod != null;
2690 return mb.IsGenericMethodDefinition;
2693 #region MemberLookup implementation
2696 // Whether we allow private members in the result (since FindMembers
2697 // uses NonPublic for both protected and private), we need to distinguish.
2700 static internal bool FilterNone (MemberInfo m, object filter_criteria)
2705 internal class Closure {
2706 internal bool private_ok;
2708 // Who is invoking us and which type is being queried currently.
2709 internal Type invocation_type;
2710 internal Type qualifier_type;
2712 // The assembly that defines the type is that is calling us
2713 internal Assembly invocation_assembly;
2714 internal IList almost_match;
2716 private bool CheckValidFamilyAccess (bool is_static, MemberInfo m)
2718 if (invocation_type == null)
2724 // A nested class has access to all the protected members visible
2726 if (qualifier_type != null
2727 && TypeManager.IsNestedChildOf (invocation_type, qualifier_type))
2730 if (invocation_type == m.DeclaringType
2731 || invocation_type.IsSubclassOf (m.DeclaringType)) {
2732 // Although a derived class can access protected members of
2733 // its base class it cannot do so through an instance of the
2734 // base class (CS1540).
2735 // => Ancestry should be: declaring_type ->* invocation_type
2736 // ->* qualified_type
2737 if (qualifier_type == null
2738 || qualifier_type == invocation_type
2739 || qualifier_type.IsSubclassOf (invocation_type))
2743 if (almost_match != null)
2744 almost_match.Add (m);
2748 bool Filter (MethodBase mb, object filter_criteria)
2750 MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
2752 if (ma == MethodAttributes.Private)
2753 return private_ok ||
2754 IsEqual (invocation_type, mb.DeclaringType) ||
2755 IsNestedChildOf (invocation_type, mb.DeclaringType);
2758 // FamAndAssem requires that we not only derivate, but we are on the
2761 if (ma == MethodAttributes.FamANDAssem){
2762 if (invocation_assembly != mb.DeclaringType.Assembly)
2766 // Assembly and FamORAssem succeed if we're in the same assembly.
2767 if ((ma == MethodAttributes.Assembly) || (ma == MethodAttributes.FamORAssem)){
2768 if (invocation_assembly == mb.DeclaringType.Assembly)
2772 // We already know that we aren't in the same assembly.
2773 if (ma == MethodAttributes.Assembly)
2776 // Family and FamANDAssem require that we derive.
2777 if ((ma == MethodAttributes.Family) || (ma == MethodAttributes.FamANDAssem)){
2778 if (invocation_type == null)
2781 if (!IsSubclassOrNestedChildOf (invocation_type, mb.DeclaringType))
2784 // Although a derived class can access protected members of its base class
2785 // it cannot do so through an instance of the base class (CS1540).
2786 if (!mb.IsStatic && (qualifier_type != null) &&
2787 !IsEqualGenericInstance (invocation_type, qualifier_type) &&
2788 TypeManager.IsSubclassOf (invocation_type, qualifier_type) &&
2789 !TypeManager.IsNestedChildOf (invocation_type, qualifier_type))
2799 bool Filter (FieldInfo fi, object filter_criteria)
2801 FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask;
2803 if (fa == FieldAttributes.Private)
2804 return private_ok ||
2805 IsEqual (invocation_type, fi.DeclaringType) ||
2806 IsNestedChildOf (invocation_type, fi.DeclaringType);
2809 // FamAndAssem requires that we not only derivate, but we are on the
2812 if (fa == FieldAttributes.FamANDAssem){
2813 if (invocation_assembly != fi.DeclaringType.Assembly)
2817 // Assembly and FamORAssem succeed if we're in the same assembly.
2818 if ((fa == FieldAttributes.Assembly) || (fa == FieldAttributes.FamORAssem)){
2819 if (invocation_assembly == fi.DeclaringType.Assembly)
2823 // We already know that we aren't in the same assembly.
2824 if (fa == FieldAttributes.Assembly)
2827 // Family and FamANDAssem require that we derive.
2828 if ((fa == FieldAttributes.Family) || (fa == FieldAttributes.FamANDAssem)){
2829 if (invocation_type == null)
2832 if (!IsSubclassOrNestedChildOf (invocation_type, fi.DeclaringType))
2835 // Although a derived class can access protected members of its base class
2836 // it cannot do so through an instance of the base class (CS1540).
2837 if (!fi.IsStatic && (qualifier_type != null) &&
2838 !IsEqualGenericInstance (invocation_type, qualifier_type) &&
2839 TypeManager.IsSubclassOf (invocation_type, qualifier_type) &&
2840 !TypeManager.IsNestedChildOf (invocation_type, qualifier_type))
2851 // This filter filters by name + whether it is ok to include private
2852 // members in the search
2854 internal bool Filter (MemberInfo m, object filter_criteria)
2857 // Hack: we know that the filter criteria will always be in the
2858 // `closure' // fields.
2861 if ((filter_criteria != null) && (m.Name != (string) filter_criteria))
2864 if (((qualifier_type == null) || (qualifier_type == invocation_type)) &&
2865 (invocation_type != null) &&
2866 IsEqual (m.DeclaringType, invocation_type))
2870 // Ugly: we need to find out the type of `m', and depending
2871 // on this, tell whether we accept or not
2873 if (m is MethodBase)
2874 return Filter ((MethodBase) m, filter_criteria);
2877 return Filter ((FieldInfo) m, filter_criteria);
2880 // EventInfos and PropertyInfos, return true because they lack
2881 // permission information, so we need to check later on the methods.
2887 static Closure closure = new Closure ();
2888 static MemberFilter FilterWithClosure_delegate = new MemberFilter (closure.Filter);
2889 static MemberFilter FilterNone_delegate = new MemberFilter (FilterNone);
2892 // Looks up a member called `name' in the `queried_type'. This lookup
2893 // is done by code that is contained in the definition for `invocation_type'
2894 // through a qualifier of type `qualifier_type' (or null if there is no qualifier).
2896 // `invocation_type' is used to check whether we're allowed to access the requested
2897 // member wrt its protection level.
2899 // When called from MemberAccess, `qualifier_type' is the type which is used to access
2900 // the requested member (`class B { A a = new A (); a.foo = 5; }'; here invocation_type
2901 // is B and qualifier_type is A). This is used to do the CS1540 check.
2903 // When resolving a SimpleName, `qualifier_type' is null.
2905 // The `qualifier_type' is used for the CS1540 check; it's normally either null or
2906 // the same than `queried_type' - except when we're being called from BaseAccess;
2907 // in this case, `invocation_type' is the current type and `queried_type' the base
2908 // type, so this'd normally trigger a CS1540.
2910 // The binding flags are `bf' and the kind of members being looked up are `mt'
2912 // The return value always includes private members which code in `invocation_type'
2913 // is allowed to access (using the specified `qualifier_type' if given); only use
2914 // BindingFlags.NonPublic to bypass the permission check.
2916 // The 'almost_match' argument is used for reporting error CS1540.
2918 // Returns an array of a single element for everything but Methods/Constructors
2919 // that might return multiple matches.
2921 public static MemberInfo [] MemberLookup (Type invocation_type, Type qualifier_type,
2922 Type queried_type, MemberTypes mt,
2923 BindingFlags original_bf, string name, IList almost_match)
2925 Timer.StartTimer (TimerType.MemberLookup);
2927 MemberInfo[] retval = RealMemberLookup (invocation_type, qualifier_type,
2928 queried_type, mt, original_bf, name, almost_match);
2930 Timer.StopTimer (TimerType.MemberLookup);
2935 static MemberInfo [] RealMemberLookup (Type invocation_type, Type qualifier_type,
2936 Type queried_type, MemberTypes mt,
2937 BindingFlags original_bf, string name, IList almost_match)
2939 BindingFlags bf = original_bf;
2941 ArrayList method_list = null;
2942 Type current_type = queried_type;
2943 bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0;
2944 bool skip_iface_check = true, used_cache = false;
2945 bool always_ok_flag = false;
2947 closure.invocation_type = invocation_type;
2948 closure.invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
2949 closure.qualifier_type = qualifier_type;
2950 closure.almost_match = almost_match;
2953 // If we are a nested class, we always have access to our container
2956 if (invocation_type != null){
2957 string invocation_name = invocation_type.FullName;
2958 if ((invocation_name != null) && (invocation_name.IndexOf ('+') != -1)){
2959 string container = queried_type.FullName + "+";
2960 int container_length = container.Length;
2962 if (invocation_name.Length > container_length){
2963 string shared = invocation_name.Substring (0, container_length);
2965 if (shared == container)
2966 always_ok_flag = true;
2971 // This is from the first time we find a method
2972 // in most cases, we do not actually find a method in the base class
2973 // so we can just ignore it, and save the arraylist allocation
2974 MemberInfo [] first_members_list = null;
2975 bool use_first_members_list = false;
2981 // `NonPublic' is lame, because it includes both protected and
2982 // private methods, so we need to control this behavior by
2983 // explicitly tracking if a private method is ok or not.
2985 // The possible cases are:
2986 // public, private and protected (internal does not come into the
2989 if ((invocation_type != null) &&
2990 ((invocation_type == current_type) ||
2991 IsNestedChildOf (invocation_type, current_type)) ||
2993 bf = original_bf | BindingFlags.NonPublic;
2997 closure.private_ok = (original_bf & BindingFlags.NonPublic) != 0;
2999 Timer.StopTimer (TimerType.MemberLookup);
3001 list = MemberLookup_FindMembers (
3002 current_type, mt, bf, name, out used_cache);
3004 Timer.StartTimer (TimerType.MemberLookup);
3007 // When queried for an interface type, the cache will automatically check all
3008 // inherited members, so we don't need to do this here. However, this only
3009 // works if we already used the cache in the first iteration of this loop.
3011 // If we used the cache in any further iteration, we can still terminate the
3012 // loop since the cache always looks in all parent classes.
3018 skip_iface_check = false;
3020 if (current_type == TypeManager.object_type)
3023 current_type = current_type.BaseType;
3026 // This happens with interfaces, they have a null
3027 // basetype. Look members up in the Object class.
3029 if (current_type == null)
3030 current_type = TypeManager.object_type;
3033 if (list.Length == 0)
3037 // Events and types are returned by both `static' and `instance'
3038 // searches, which means that our above FindMembers will
3039 // return two copies of the same.
3041 if (list.Length == 1 && !(list [0] is MethodBase)){
3046 // Multiple properties: we query those just to find out the indexer
3049 if (list [0] is PropertyInfo)
3053 // We found an event: the cache lookup returns both the event and
3054 // its private field.
3056 if (list [0] is EventInfo) {
3057 if ((list.Length == 2) && (list [1] is FieldInfo))
3058 return new MemberInfo [] { list [0] };
3065 // We found methods, turn the search into "method scan"
3069 if (first_members_list != null) {
3070 if (use_first_members_list) {
3071 method_list = CopyNewMethods (method_list, first_members_list);
3072 use_first_members_list = false;
3075 method_list = CopyNewMethods (method_list, list);
3077 first_members_list = list;
3078 use_first_members_list = true;
3080 mt &= (MemberTypes.Method | MemberTypes.Constructor);
3082 } while (searching);
3084 if (use_first_members_list) {
3085 foreach (MemberInfo mi in first_members_list) {
3086 if (! (mi is MethodBase)) {
3087 method_list = CopyNewMethods (method_list, first_members_list);
3088 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
3091 return (MemberInfo []) first_members_list;
3094 if (method_list != null && method_list.Count > 0) {
3095 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
3098 // This happens if we already used the cache in the first iteration, in this case
3099 // the cache already looked in all interfaces.
3101 if (skip_iface_check)
3105 // Interfaces do not list members they inherit, so we have to
3108 if (!queried_type.IsInterface)
3111 if (queried_type.IsArray)
3112 queried_type = TypeManager.array_type;
3114 Type [] ifaces = GetInterfaces (queried_type);
3118 foreach (Type itype in ifaces){
3121 x = MemberLookup (null, null, itype, mt, bf, name, null);
3130 // This is used to extract properties and event declarations from a type
3132 static MemberInfo [] SpecialContainerLookup (Type t, bool is_static)
3134 BindingFlags bf = BindingFlags.DeclaredOnly | (is_static ? BindingFlags.Static : BindingFlags.Instance);
3136 bf |= BindingFlags.Public | BindingFlags.NonPublic;
3138 if (t is TypeBuilder) {
3139 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
3141 return (MemberInfo []) decl.FindMembers (
3142 MemberTypes.Property | MemberTypes.Event,
3143 bf, FilterNone_delegate, null);
3145 return t.FindMembers (MemberTypes.Property | MemberTypes.Event,
3146 bf, FilterNone_delegate, null);
3151 public static bool IsSpecialMethod (MethodBase mb)
3153 Type t = mb.DeclaringType;
3155 MemberInfo [] matches = TypeManager.SpecialContainerLookup (t, mb.IsStatic);
3156 if (matches == null)
3159 foreach (MemberInfo mi in matches){
3160 if (mi is PropertyBuilder){
3161 Pair p = (Pair) properties [mi];
3163 if (p.First == mb || p.Second == mb)
3165 } else if (mi is PropertyInfo){
3166 MethodInfo [] methods = ((PropertyInfo) mi).GetAccessors (true);
3168 foreach (MethodInfo m in methods){
3172 } else if (mi is MyEventBuilder){
3173 Pair p = (Pair) events [mi];
3175 if (p.First == mb || p.Second == mb)
3177 } else if (mi is EventInfo){
3178 EventInfo ei = ((EventInfo) mi);
3180 if (ei.GetAddMethod (true) == mb)
3183 if (ei.GetRemoveMethod (true) == mb)
3186 if (ei.GetRaiseMethod (true) == mb)
3192 // Now check if it is an operator method
3196 if (s.StartsWith ("op_")){
3197 foreach (string name in Unary.oper_names){
3202 foreach (string name in Binary.oper_names){
3216 /// There is exactly one instance of this class per type.
3218 public sealed class TypeHandle : IMemberContainer {
3219 public readonly TypeHandle BaseType;
3221 readonly int id = ++next_id;
3222 static int next_id = 0;
3225 /// Lookup a TypeHandle instance for the given type. If the type doesn't have
3226 /// a TypeHandle yet, a new instance of it is created. This static method
3227 /// ensures that we'll only have one TypeHandle instance per type.
3229 public static TypeHandle GetTypeHandle (Type t)
3231 TypeHandle handle = (TypeHandle) type_hash [t];
3235 handle = new TypeHandle (t);
3236 type_hash.Add (t, handle);
3240 public static void CleanUp ()
3246 /// Returns the TypeHandle for TypeManager.object_type.
3248 public static IMemberContainer ObjectType {
3250 if (object_type != null)
3253 object_type = GetTypeHandle (TypeManager.object_type);
3260 /// Returns the TypeHandle for TypeManager.array_type.
3262 public static IMemberContainer ArrayType {
3264 if (array_type != null)
3267 array_type = GetTypeHandle (TypeManager.array_type);
3273 private static PtrHashtable type_hash = new PtrHashtable ();
3275 private static TypeHandle object_type = null;
3276 private static TypeHandle array_type = null;
3279 private string full_name;
3280 private bool is_interface;
3281 private MemberCache member_cache;
3283 private TypeHandle (Type type)
3286 full_name = type.FullName != null ? type.FullName : type.Name;
3287 if (type.BaseType != null)
3288 BaseType = GetTypeHandle (type.BaseType);
3289 this.is_interface = type.IsInterface || type.IsGenericParameter;
3290 this.member_cache = new MemberCache (this);
3293 // IMemberContainer methods
3295 public string Name {
3307 public IMemberContainer ParentContainer {
3313 public bool IsInterface {
3315 return is_interface;
3319 public MemberList GetMembers (MemberTypes mt, BindingFlags bf)
3321 MemberInfo [] members;
3322 if (type is GenericTypeParameterBuilder)
3323 return MemberList.Empty;
3324 if (mt == MemberTypes.Event)
3325 members = type.GetEvents (bf | BindingFlags.DeclaredOnly);
3327 members = type.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
3329 Array.Reverse (members);
3331 return new MemberList (members);
3334 // IMemberFinder methods
3336 public MemberList FindMembers (MemberTypes mt, BindingFlags bf, string name,
3337 MemberFilter filter, object criteria)
3339 return new MemberList (member_cache.FindMembers (mt, bf, name, filter, criteria));
3342 public MemberCache MemberCache {
3344 return member_cache;
3348 public override string ToString ()
3350 if (BaseType != null)
3351 return "TypeHandle (" + id + "," + Name + " : " + BaseType + ")";
3353 return "TypeHandle (" + id + "," + Name + ")";