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 default_member_type;
67 static public Type iasyncresult_type;
68 static public Type asynccallback_type;
69 static public Type intptr_type;
70 static public Type monitor_type;
71 static public Type runtime_field_handle_type;
72 static public Type attribute_type;
73 static public Type attribute_usage_type;
74 static public Type dllimport_type;
75 static public Type unverifiable_code_type;
76 static public Type methodimpl_attr_type;
77 static public Type marshal_as_attr_type;
78 static public Type param_array_type;
79 static public Type guid_attr_type;
80 static public Type void_ptr_type;
81 static public Type indexer_name_type;
82 static public Type exception_type;
83 static public Type invalid_operation_exception_type;
84 static public object obsolete_attribute_type;
85 static public object conditional_attribute_type;
86 static public Type in_attribute_type;
89 // An empty array of types
91 static public Type [] NoTypes;
92 static public TypeExpr [] NoTypeExprs;
96 // Expressions representing the internal types. Used during declaration
99 static public TypeExpr system_object_expr, system_string_expr;
100 static public TypeExpr system_boolean_expr, system_decimal_expr;
101 static public TypeExpr system_single_expr, system_double_expr;
102 static public TypeExpr system_sbyte_expr, system_byte_expr;
103 static public TypeExpr system_int16_expr, system_uint16_expr;
104 static public TypeExpr system_int32_expr, system_uint32_expr;
105 static public TypeExpr system_int64_expr, system_uint64_expr;
106 static public TypeExpr system_char_expr, system_void_expr;
107 static public TypeExpr system_asynccallback_expr;
108 static public TypeExpr system_iasyncresult_expr;
109 static public TypeExpr system_valuetype_expr;
112 // This is only used when compiling corlib
114 static public Type system_int32_type;
115 static public Type system_array_type;
116 static public Type system_type_type;
117 static public Type system_assemblybuilder_type;
118 static public MethodInfo system_int_array_get_length;
119 static public MethodInfo system_int_array_get_rank;
120 static public MethodInfo system_object_array_clone;
121 static public MethodInfo system_int_array_get_length_int;
122 static public MethodInfo system_int_array_get_lower_bound_int;
123 static public MethodInfo system_int_array_get_upper_bound_int;
124 static public MethodInfo system_void_array_copyto_array_int;
128 // Internal, not really used outside
130 static Type runtime_helpers_type;
133 // These methods are called by code generated by the compiler
135 static public MethodInfo string_concat_string_string;
136 static public MethodInfo string_concat_string_string_string;
137 static public MethodInfo string_concat_string_string_string_string;
138 static public MethodInfo string_concat_object_object;
139 static public MethodInfo string_isinterneted_string;
140 static public MethodInfo system_type_get_type_from_handle;
141 static public MethodInfo object_getcurrent_void;
142 static public MethodInfo bool_movenext_void;
143 static public MethodInfo ienumerable_getenumerator_void;
144 static public MethodInfo void_reset_void;
145 static public MethodInfo void_dispose_void;
146 static public MethodInfo void_monitor_enter_object;
147 static public MethodInfo void_monitor_exit_object;
148 static public MethodInfo void_initializearray_array_fieldhandle;
149 static public MethodInfo int_getlength_int;
150 static public MethodInfo delegate_combine_delegate_delegate;
151 static public MethodInfo delegate_remove_delegate_delegate;
152 static public MethodInfo int_get_offset_to_string_data;
153 static public MethodInfo int_array_get_length;
154 static public MethodInfo int_array_get_rank;
155 static public MethodInfo object_array_clone;
156 static public MethodInfo int_array_get_length_int;
157 static public MethodInfo int_array_get_lower_bound_int;
158 static public MethodInfo int_array_get_upper_bound_int;
159 static public MethodInfo void_array_copyto_array_int;
162 // The attribute constructors.
164 static public ConstructorInfo object_ctor;
165 static public ConstructorInfo cons_param_array_attribute;
166 static public ConstructorInfo void_decimal_ctor_five_args;
167 static public ConstructorInfo unverifiable_code_ctor;
168 static public ConstructorInfo invalid_operation_ctor;
171 // Holds the Array of Assemblies that have been loaded
172 // (either because it is the default or the user used the
173 // -r command line option)
175 static Assembly [] assemblies;
178 // Keeps a list of module builders. We used this to do lookups
179 // on the modulebuilder using GetType -- needed for arrays
181 static ModuleBuilder [] modules;
184 // This is the type_cache from the assemblies to avoid
185 // hitting System.Reflection on every lookup.
187 static Hashtable types;
190 // This is used to hotld the corresponding TypeContainer objects
191 // since we need this in FindMembers
193 static Hashtable typecontainers;
196 // Keeps track of those types that are defined by the
199 static ArrayList user_types;
201 static PtrHashtable builder_to_declspace;
204 // Tracks the interfaces implemented by typebuilders. We only
205 // enter those who do implement or or more interfaces
207 static PtrHashtable builder_to_ifaces;
210 // Maps MethodBase.RuntimeTypeHandle to a Type array that contains
211 // the arguments to the method
213 static Hashtable method_arguments;
216 // Maps PropertyBuilder to a Type array that contains
217 // the arguments to the indexer
219 static Hashtable indexer_arguments;
222 // Maybe `method_arguments' should be replaced and only
223 // method_internal_params should be kept?
225 static Hashtable method_internal_params;
228 // Keeps track of attribute types
231 static Hashtable builder_to_attr;
234 // Keeps track of methods
237 static Hashtable builder_to_method;
245 /// A filter for Findmembers that uses the Signature object to
248 static bool SignatureFilter (MemberInfo mi, object criteria)
250 Signature sig = (Signature) criteria;
252 if (!(mi is MethodBase))
255 if (mi.Name != sig.name)
258 int count = sig.args.Length;
260 if (mi is MethodBuilder || mi is ConstructorBuilder){
261 Type [] candidate_args = GetArgumentTypes ((MethodBase) mi);
263 if (candidate_args.Length != count)
266 for (int i = 0; i < count; i++)
267 if (candidate_args [i] != sig.args [i])
272 ParameterInfo [] pars = ((MethodBase) mi).GetParameters ();
274 if (pars.Length != count)
277 for (int i = 0; i < count; i++)
278 if (pars [i].ParameterType != sig.args [i])
284 // A delegate that points to the filter above.
285 static MemberFilter signature_filter;
288 // These are expressions that represent some of the internal data types, used
291 static void InitExpressionTypes ()
293 system_object_expr = new TypeLookupExpression ("System.Object");
294 system_string_expr = new TypeLookupExpression ("System.String");
295 system_boolean_expr = new TypeLookupExpression ("System.Boolean");
296 system_decimal_expr = new TypeLookupExpression ("System.Decimal");
297 system_single_expr = new TypeLookupExpression ("System.Single");
298 system_double_expr = new TypeLookupExpression ("System.Double");
299 system_sbyte_expr = new TypeLookupExpression ("System.SByte");
300 system_byte_expr = new TypeLookupExpression ("System.Byte");
301 system_int16_expr = new TypeLookupExpression ("System.Int16");
302 system_uint16_expr = new TypeLookupExpression ("System.UInt16");
303 system_int32_expr = new TypeLookupExpression ("System.Int32");
304 system_uint32_expr = new TypeLookupExpression ("System.UInt32");
305 system_int64_expr = new TypeLookupExpression ("System.Int64");
306 system_uint64_expr = new TypeLookupExpression ("System.UInt64");
307 system_char_expr = new TypeLookupExpression ("System.Char");
308 system_void_expr = new TypeLookupExpression ("System.Void");
309 system_asynccallback_expr = new TypeLookupExpression ("System.AsyncCallback");
310 system_iasyncresult_expr = new TypeLookupExpression ("System.IAsyncResult");
311 system_valuetype_expr = new TypeLookupExpression ("System.ValueType");
314 public static void ResolveExpressionTypes (EmitContext ec)
316 system_object_expr.ResolveType (ec);
317 system_string_expr.ResolveType (ec);
318 system_boolean_expr.ResolveType (ec);
319 system_decimal_expr.ResolveType (ec);
320 system_single_expr.ResolveType (ec);
321 system_double_expr.ResolveType (ec);
322 system_sbyte_expr.ResolveType (ec);
323 system_byte_expr.ResolveType (ec);
324 system_int16_expr.ResolveType (ec);
325 system_uint16_expr.ResolveType (ec);
326 system_int32_expr.ResolveType (ec);
327 system_uint32_expr.ResolveType (ec);
328 system_int64_expr.ResolveType (ec);
329 system_uint64_expr.ResolveType (ec);
330 system_char_expr.ResolveType (ec);
331 system_void_expr.ResolveType (ec);
332 system_asynccallback_expr.ResolveType (ec);
333 system_iasyncresult_expr.ResolveType (ec);
334 system_valuetype_expr.ResolveType (ec);
337 static TypeManager ()
339 assemblies = new Assembly [0];
341 user_types = new ArrayList ();
343 types = new Hashtable ();
344 typecontainers = new Hashtable ();
346 builder_to_declspace = new PtrHashtable ();
347 builder_to_attr = new PtrHashtable ();
348 builder_to_method = new PtrHashtable ();
349 method_arguments = new PtrHashtable ();
350 method_internal_params = new PtrHashtable ();
351 indexer_arguments = new PtrHashtable ();
352 builder_to_ifaces = new PtrHashtable ();
354 NoTypes = new Type [0];
355 NoTypeExprs = new TypeExpr [0];
357 signature_filter = new MemberFilter (SignatureFilter);
358 InitExpressionTypes ();
361 public static void HandleDuplicate (string name, Type t)
363 Type prev = (Type) types [name];
364 TypeContainer tc = builder_to_declspace [prev] as TypeContainer;
368 // This probably never happens, as we catch this before
370 Report.Error (-17, "The type `" + name + "' has already been defined.");
375 tc = builder_to_declspace [t] as TypeContainer;
378 1595, "The type `" + name + "' is defined in an existing assembly;"+
379 " Using the new definition from: " + tc.Location);
382 1595, "The type `" + name + "' is defined in an existing assembly;");
385 Report.Warning (1595, "Previously defined in: " + prev.Assembly.FullName);
391 public static void AddUserType (string name, TypeBuilder t, Type [] ifaces)
396 HandleDuplicate (name, t);
401 builder_to_ifaces [t] = ifaces;
405 // This entry point is used by types that we define under the covers
407 public static void RegisterBuilder (TypeBuilder tb, Type [] ifaces)
410 builder_to_ifaces [tb] = ifaces;
413 public static void AddUserType (string name, TypeBuilder t, TypeContainer tc, Type [] ifaces)
415 builder_to_declspace.Add (t, tc);
416 typecontainers.Add (name, tc);
417 AddUserType (name, t, ifaces);
420 public static void AddDelegateType (string name, TypeBuilder t, Delegate del)
425 HandleDuplicate (name, t);
428 builder_to_declspace.Add (t, del);
431 public static void AddEnumType (string name, TypeBuilder t, Enum en)
436 HandleDuplicate (name, t);
438 builder_to_declspace.Add (t, en);
441 public static void AddUserInterface (string name, TypeBuilder t, Interface i, Type [] ifaces)
443 AddUserType (name, t, ifaces);
444 builder_to_declspace.Add (t, i);
447 public static void AddMethod (MethodBuilder builder, MethodData method)
449 builder_to_method.Add (builder, method);
452 public static void RegisterAttrType (Type t, TypeContainer tc)
454 builder_to_attr.Add (t, tc);
458 /// Returns the DeclSpace whose Type is `t' or null if there is no
459 /// DeclSpace for `t' (ie, the Type comes from a library)
461 public static DeclSpace LookupDeclSpace (Type t)
463 return builder_to_declspace [t] as DeclSpace;
467 /// Returns the TypeContainer whose Type is `t' or null if there is no
468 /// TypeContainer for `t' (ie, the Type comes from a library)
470 public static TypeContainer LookupTypeContainer (Type t)
472 return builder_to_declspace [t] as TypeContainer;
475 public static IMemberContainer LookupMemberContainer (Type t)
477 if (t is TypeBuilder) {
478 IMemberContainer container = builder_to_declspace [t] as IMemberContainer;
479 if (container != null)
483 return TypeHandle.GetTypeHandle (t);
486 public static Interface LookupInterface (Type t)
488 return builder_to_declspace [t] as Interface;
491 public static Delegate LookupDelegate (Type t)
493 return builder_to_declspace [t] as Delegate;
496 public static Enum LookupEnum (Type t)
498 return builder_to_declspace [t] as Enum;
501 public static TypeContainer LookupAttr (Type t)
503 return (TypeContainer) builder_to_attr [t];
507 /// Registers an assembly to load types from.
509 public static void AddAssembly (Assembly a)
511 int top = assemblies.Length;
512 Assembly [] n = new Assembly [top + 1];
514 assemblies.CopyTo (n, 0);
521 /// Registers a module builder to lookup types from
523 public static void AddModule (ModuleBuilder mb)
525 int top = modules != null ? modules.Length : 0;
526 ModuleBuilder [] n = new ModuleBuilder [top + 1];
529 modules.CopyTo (n, 0);
534 static Hashtable references = new Hashtable ();
537 // Gets the reference to T version of the Type (T&)
539 public static Type GetReferenceType (Type t)
541 string tname = t.FullName + "&";
543 Type ret = t.Assembly.GetType (tname);
546 // If the type comes from the assembly we are building
547 // We need the Hashtable, because .NET 1.1 will return different instance types
548 // every time we call ModuleBuilder.GetType.
551 if (references [t] == null)
552 references [t] = CodeGen.ModuleBuilder.GetType (tname);
553 ret = (Type) references [t];
559 static Hashtable pointers = new Hashtable ();
562 // Gets the pointer to T version of the Type (T*)
564 public static Type GetPointerType (Type t)
566 string tname = t.FullName + "*";
568 Type ret = t.Assembly.GetType (tname);
571 // If the type comes from the assembly we are building
572 // We need the Hashtable, because .NET 1.1 will return different instance types
573 // every time we call ModuleBuilder.GetType.
576 if (pointers [t] == null)
577 pointers [t] = CodeGen.ModuleBuilder.GetType (tname);
579 ret = (Type) pointers [t];
586 // Low-level lookup, cache-less
588 static Type LookupTypeReflection (string name)
592 foreach (Assembly a in assemblies){
593 t = a.GetType (name);
598 TypeAttributes ta = t.Attributes & TypeAttributes.VisibilityMask;
599 if (ta == TypeAttributes.NotPublic ||
600 ta == TypeAttributes.NestedPrivate ||
601 ta == TypeAttributes.NestedAssembly ||
602 ta == TypeAttributes.NestedFamANDAssem){
605 // In .NET pointers turn out to be private, even if their
606 // element type is not
609 t = t.GetElementType ();
619 foreach (ModuleBuilder mb in modules) {
620 t = mb.GetType (name);
628 static Hashtable negative_hits = new Hashtable ();
631 // This function is used when you want to avoid the lookups, and want to go
632 // directly to the source. This will use the cache.
634 // Notice that bypassing the cache is bad, because on Microsoft.NET runtime
635 // GetType ("DynamicType[]") != GetType ("DynamicType[]"), and there is no
636 // way to test things other than doing a fullname compare
638 public static Type LookupTypeDirect (string name)
640 Type t = (Type) types [name];
644 t = LookupTypeReflection (name);
653 /// Returns the Type associated with @name, takes care of the fact that
654 /// reflection expects nested types to be separated from the main type
655 /// with a "+" instead of a "."
657 public static Type LookupType (string name)
662 // First lookup in user defined and cached values
665 t = (Type) types [name];
669 // Two thirds of the failures are caught here.
670 if (negative_hits.Contains (name))
673 string [] elements = name.Split ('.');
674 int count = elements.Length;
676 for (int n = 1; n <= count; n++){
677 string top_level_type = String.Join (".", elements, 0, n);
679 // One third of the failures are caught here.
680 if (negative_hits.Contains (top_level_type))
683 t = (Type) types [top_level_type];
685 t = LookupTypeReflection (top_level_type);
687 negative_hits [top_level_type] = true;
698 // We know that System.Object does not have children, and since its the parent of
699 // all the objects, it always gets probbed for inner classes.
701 if (top_level_type == "System.Object")
704 string newt = top_level_type + "+" + String.Join ("+", elements, n, count - n);
705 //Console.WriteLine ("Looking up: " + newt + " " + name);
706 t = LookupTypeReflection (newt);
708 negative_hits [name] = true;
713 negative_hits [name] = true;
718 /// Computes the namespaces that we import from the assemblies we reference.
720 public static void ComputeNamespaces ()
722 MethodInfo assembly_get_namespaces = typeof (Assembly).GetMethod ("GetNamespaces");
725 // First add the assembly namespaces
727 if (assembly_get_namespaces != null){
728 int count = assemblies.Length;
731 for (int i = 0; i < count; i++){
732 Assembly a = assemblies [i];
733 string [] namespaces = (string []) assembly_get_namespaces.Invoke (a, null);
734 foreach (string ns in namespaces){
737 Namespace.LookupNamespace (ns, true);
741 foreach (Assembly a in assemblies){
742 foreach (Type t in a.GetTypes ()){
743 string ns = t.Namespace;
745 // t.Namespace returns null for <PrivateImplDetails>
746 if (ns == ""|| ns == null)
748 Namespace.LookupNamespace (ns, true);
754 public static bool NamespaceClash (string name, Location loc)
756 if (Namespace.LookupNamespace (name, false) == null)
759 Report.Error (519, loc, String.Format ("`{0}' clashes with a predefined namespace", name));
764 /// Returns the C# name of a type if possible, or the full type name otherwise
766 static public string CSharpName (Type t)
768 return Regex.Replace (t.FullName,
770 @"(Int32|UInt32|Int16|UInt16|Int64|UInt64|" +
771 @"Single|Double|Char|Decimal|Byte|SByte|Object|" +
772 @"Boolean|String|Void)" +
774 new MatchEvaluator (CSharpNameMatch));
777 static String CSharpNameMatch (Match match)
779 string s = match.Groups [1].Captures [0].Value;
781 Replace ("int32", "int").
782 Replace ("uint32", "uint").
783 Replace ("int16", "short").
784 Replace ("uint16", "ushort").
785 Replace ("int64", "long").
786 Replace ("uint64", "ulong").
787 Replace ("single", "float").
788 Replace ("boolean", "bool")
789 + match.Groups [2].Captures [0].Value;
793 /// Returns the signature of the method
795 static public string CSharpSignature (MethodBase mb)
800 // FIXME: We should really have a single function to do
801 // everything instead of the following 5 line pattern
803 ParameterData iparams = LookupParametersByBuilder (mb);
805 if (iparams == null){
806 ParameterInfo [] pi = mb.GetParameters ();
807 iparams = new ReflectionParameters (pi);
810 for (int i = 0; i < iparams.Count; i++) {
814 sig += iparams.ParameterDesc(i);
818 return mb.DeclaringType.Name + "." + mb.Name + sig;
822 /// Looks up a type, and aborts if it is not found. This is used
823 /// by types required by the compiler
825 static Type CoreLookupType (string name)
827 Type t = LookupTypeDirect (name);
830 Report.Error (518, "The predefined type `" + name + "' is not defined or imported");
831 Environment.Exit (0);
838 /// Returns the MethodInfo for a method named `name' defined
839 /// in type `t' which takes arguments of types `args'
841 static MethodInfo GetMethod (Type t, string name, Type [] args, bool report_errors)
849 list = FindMembers (t, MemberTypes.Method, instance_and_static | BindingFlags.Public,
850 signature_filter, sig);
851 if (list.Count == 0) {
853 Report.Error (-19, "Can not find the core function `" + name + "'");
857 MethodInfo mi = list [0] as MethodInfo;
860 Report.Error (-19, "Can not find the core function `" + name + "'");
867 static MethodInfo GetMethod (Type t, string name, Type [] args)
869 return GetMethod (t, name, args, true);
874 /// Returns the ConstructorInfo for "args"
876 static ConstructorInfo GetConstructor (Type t, Type [] args)
884 list = FindMembers (t, MemberTypes.Constructor,
885 instance_and_static | BindingFlags.Public | BindingFlags.DeclaredOnly,
886 signature_filter, sig);
887 if (list.Count == 0){
888 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
892 ConstructorInfo ci = list [0] as ConstructorInfo;
894 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
901 public static void InitEnumUnderlyingTypes ()
904 int32_type = CoreLookupType ("System.Int32");
905 int64_type = CoreLookupType ("System.Int64");
906 uint32_type = CoreLookupType ("System.UInt32");
907 uint64_type = CoreLookupType ("System.UInt64");
908 byte_type = CoreLookupType ("System.Byte");
909 sbyte_type = CoreLookupType ("System.SByte");
910 short_type = CoreLookupType ("System.Int16");
911 ushort_type = CoreLookupType ("System.UInt16");
915 /// The types have to be initialized after the initial
916 /// population of the type has happened (for example, to
917 /// bootstrap the corlib.dll
919 public static void InitCoreTypes ()
921 object_type = CoreLookupType ("System.Object");
922 value_type = CoreLookupType ("System.ValueType");
924 InitEnumUnderlyingTypes ();
926 char_type = CoreLookupType ("System.Char");
927 string_type = CoreLookupType ("System.String");
928 float_type = CoreLookupType ("System.Single");
929 double_type = CoreLookupType ("System.Double");
930 char_ptr_type = CoreLookupType ("System.Char*");
931 decimal_type = CoreLookupType ("System.Decimal");
932 bool_type = CoreLookupType ("System.Boolean");
933 enum_type = CoreLookupType ("System.Enum");
935 multicast_delegate_type = CoreLookupType ("System.MulticastDelegate");
936 delegate_type = CoreLookupType ("System.Delegate");
938 array_type = CoreLookupType ("System.Array");
939 void_type = CoreLookupType ("System.Void");
940 type_type = CoreLookupType ("System.Type");
942 runtime_field_handle_type = CoreLookupType ("System.RuntimeFieldHandle");
943 runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices.RuntimeHelpers");
944 default_member_type = CoreLookupType ("System.Reflection.DefaultMemberAttribute");
945 runtime_handle_type = CoreLookupType ("System.RuntimeTypeHandle");
946 asynccallback_type = CoreLookupType ("System.AsyncCallback");
947 iasyncresult_type = CoreLookupType ("System.IAsyncResult");
948 ienumerator_type = CoreLookupType ("System.Collections.IEnumerator");
949 ienumerable_type = CoreLookupType ("System.Collections.IEnumerable");
950 idisposable_type = CoreLookupType ("System.IDisposable");
951 icloneable_type = CoreLookupType ("System.ICloneable");
952 monitor_type = CoreLookupType ("System.Threading.Monitor");
953 intptr_type = CoreLookupType ("System.IntPtr");
955 attribute_type = CoreLookupType ("System.Attribute");
956 attribute_usage_type = CoreLookupType ("System.AttributeUsageAttribute");
957 dllimport_type = CoreLookupType ("System.Runtime.InteropServices.DllImportAttribute");
958 methodimpl_attr_type = CoreLookupType ("System.Runtime.CompilerServices.MethodImplAttribute");
959 marshal_as_attr_type = CoreLookupType ("System.Runtime.InteropServices.MarshalAsAttribute");
960 param_array_type = CoreLookupType ("System.ParamArrayAttribute");
961 in_attribute_type = CoreLookupType ("System.Runtime.InteropServices.InAttribute");
964 // Sigh. Remove this before the release. Wonder what versions of Mono
965 // people are running.
967 guid_attr_type = LookupType ("System.Runtime.InteropServices.GuidAttribute");
969 unverifiable_code_type= CoreLookupType ("System.Security.UnverifiableCodeAttribute");
971 void_ptr_type = CoreLookupType ("System.Void*");
973 indexer_name_type = CoreLookupType ("System.Runtime.CompilerServices.IndexerNameAttribute");
975 exception_type = CoreLookupType ("System.Exception");
976 invalid_operation_exception_type = CoreLookupType ("System.InvalidOperationException");
981 obsolete_attribute_type = CoreLookupType ("System.ObsoleteAttribute");
982 conditional_attribute_type = CoreLookupType ("System.Diagnostics.ConditionalAttribute");
985 // When compiling corlib, store the "real" types here.
987 if (!RootContext.StdLib) {
988 system_int32_type = typeof (System.Int32);
989 system_array_type = typeof (System.Array);
990 system_type_type = typeof (System.Type);
991 system_assemblybuilder_type = typeof (System.Reflection.Emit.AssemblyBuilder);
993 Type [] void_arg = { };
994 system_int_array_get_length = GetMethod (
995 system_array_type, "get_Length", void_arg);
996 system_int_array_get_rank = GetMethod (
997 system_array_type, "get_Rank", void_arg);
998 system_object_array_clone = GetMethod (
999 system_array_type, "Clone", void_arg);
1001 Type [] system_int_arg = { system_int32_type };
1002 system_int_array_get_length_int = GetMethod (
1003 system_array_type, "GetLength", system_int_arg);
1004 system_int_array_get_upper_bound_int = GetMethod (
1005 system_array_type, "GetUpperBound", system_int_arg);
1006 system_int_array_get_lower_bound_int = GetMethod (
1007 system_array_type, "GetLowerBound", system_int_arg);
1009 Type [] system_array_int_arg = { system_array_type, system_int32_type };
1010 system_void_array_copyto_array_int = GetMethod (
1011 system_array_type, "CopyTo", system_array_int_arg);
1013 Type [] system_3_type_arg = {
1014 system_type_type, system_type_type, system_type_type };
1015 Type [] system_4_type_arg = {
1016 system_type_type, system_type_type, system_type_type, system_type_type };
1018 MethodInfo set_corlib_type_builders = GetMethod (
1019 system_assemblybuilder_type, "SetCorlibTypeBuilders",
1020 system_4_type_arg, false);
1022 if (set_corlib_type_builders != null) {
1023 object[] args = new object [4];
1024 args [0] = object_type;
1025 args [1] = value_type;
1026 args [2] = enum_type;
1027 args [3] = void_type;
1029 set_corlib_type_builders.Invoke (CodeGen.AssemblyBuilder, args);
1031 // Compatibility for an older version of the class libs.
1032 set_corlib_type_builders = GetMethod (
1033 system_assemblybuilder_type, "SetCorlibTypeBuilders",
1034 system_3_type_arg, true);
1036 if (set_corlib_type_builders == null) {
1037 Report.Error (-26, "Corlib compilation is not supported in Microsoft.NET due to bugs in it");
1041 object[] args = new object [3];
1042 args [0] = object_type;
1043 args [1] = value_type;
1044 args [2] = enum_type;
1046 set_corlib_type_builders.Invoke (CodeGen.AssemblyBuilder, args);
1052 // The helper methods that are used by the compiler
1054 public static void InitCodeHelpers ()
1057 // Now load the default methods that we use.
1059 Type [] string_string = { string_type, string_type };
1060 string_concat_string_string = GetMethod (
1061 string_type, "Concat", string_string);
1062 Type [] string_string_string = { string_type, string_type, string_type };
1063 string_concat_string_string_string = GetMethod (
1064 string_type, "Concat", string_string_string);
1065 Type [] string_string_string_string = { string_type, string_type, string_type, string_type };
1066 string_concat_string_string_string_string = GetMethod (
1067 string_type, "Concat", string_string_string_string);
1069 Type [] object_object = { object_type, object_type };
1070 string_concat_object_object = GetMethod (
1071 string_type, "Concat", object_object);
1073 Type [] string_ = { string_type };
1074 string_isinterneted_string = GetMethod (
1075 string_type, "IsInterned", string_);
1077 Type [] runtime_type_handle = { runtime_handle_type };
1078 system_type_get_type_from_handle = GetMethod (
1079 type_type, "GetTypeFromHandle", runtime_type_handle);
1081 Type [] delegate_delegate = { delegate_type, delegate_type };
1082 delegate_combine_delegate_delegate = GetMethod (
1083 delegate_type, "Combine", delegate_delegate);
1085 delegate_remove_delegate_delegate = GetMethod (
1086 delegate_type, "Remove", delegate_delegate);
1091 Type [] void_arg = { };
1092 object_getcurrent_void = GetMethod (
1093 ienumerator_type, "get_Current", void_arg);
1094 bool_movenext_void = GetMethod (
1095 ienumerator_type, "MoveNext", void_arg);
1096 void_reset_void = GetMethod (
1097 ienumerator_type, "Reset", void_arg);
1098 void_dispose_void = GetMethod (
1099 idisposable_type, "Dispose", void_arg);
1100 int_get_offset_to_string_data = GetMethod (
1101 runtime_helpers_type, "get_OffsetToStringData", void_arg);
1102 int_array_get_length = GetMethod (
1103 array_type, "get_Length", void_arg);
1104 int_array_get_rank = GetMethod (
1105 array_type, "get_Rank", void_arg);
1106 ienumerable_getenumerator_void = GetMethod (
1107 ienumerable_type, "GetEnumerator", void_arg);
1112 Type [] int_arg = { int32_type };
1113 int_array_get_length_int = GetMethod (
1114 array_type, "GetLength", int_arg);
1115 int_array_get_upper_bound_int = GetMethod (
1116 array_type, "GetUpperBound", int_arg);
1117 int_array_get_lower_bound_int = GetMethod (
1118 array_type, "GetLowerBound", int_arg);
1121 // System.Array methods
1123 object_array_clone = GetMethod (
1124 array_type, "Clone", void_arg);
1125 Type [] array_int_arg = { array_type, int32_type };
1126 void_array_copyto_array_int = GetMethod (
1127 array_type, "CopyTo", array_int_arg);
1132 Type [] object_arg = { object_type };
1133 void_monitor_enter_object = GetMethod (
1134 monitor_type, "Enter", object_arg);
1135 void_monitor_exit_object = GetMethod (
1136 monitor_type, "Exit", object_arg);
1138 Type [] array_field_handle_arg = { array_type, runtime_field_handle_type };
1140 void_initializearray_array_fieldhandle = GetMethod (
1141 runtime_helpers_type, "InitializeArray", array_field_handle_arg);
1146 int_getlength_int = GetMethod (
1147 array_type, "GetLength", int_arg);
1150 // Decimal constructors
1152 Type [] dec_arg = { int32_type, int32_type, int32_type, bool_type, byte_type };
1153 void_decimal_ctor_five_args = GetConstructor (
1154 decimal_type, dec_arg);
1159 cons_param_array_attribute = GetConstructor (
1160 param_array_type, void_arg);
1162 unverifiable_code_ctor = GetConstructor (
1163 unverifiable_code_type, void_arg);
1166 // InvalidOperationException
1168 invalid_operation_ctor = GetConstructor (
1169 invalid_operation_exception_type, void_arg);
1173 object_ctor = GetConstructor (object_type, void_arg);
1177 const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance;
1179 static Hashtable type_hash = new Hashtable ();
1182 /// This is the "old", non-cache based FindMembers() function. We cannot use
1183 /// the cache here because there is no member name argument.
1185 public static MemberList FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1186 MemberFilter filter, object criteria)
1188 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
1191 // `builder_to_declspace' contains all dynamic types.
1195 Timer.StartTimer (TimerType.FindMembers);
1196 list = decl.FindMembers (mt, bf, filter, criteria);
1197 Timer.StopTimer (TimerType.FindMembers);
1202 // We have to take care of arrays specially, because GetType on
1203 // a TypeBuilder array will return a Type, not a TypeBuilder,
1204 // and we can not call FindMembers on this type.
1206 if (t.IsSubclassOf (TypeManager.array_type))
1207 return new MemberList (TypeManager.array_type.FindMembers (mt, bf, filter, criteria));
1210 // Since FindMembers will not lookup both static and instance
1211 // members, we emulate this behaviour here.
1213 if ((bf & instance_and_static) == instance_and_static){
1214 MemberInfo [] i_members = t.FindMembers (
1215 mt, bf & ~BindingFlags.Static, filter, criteria);
1217 int i_len = i_members.Length;
1219 MemberInfo one = i_members [0];
1222 // If any of these are present, we are done!
1224 if ((one is Type) || (one is EventInfo) || (one is FieldInfo))
1225 return new MemberList (i_members);
1228 MemberInfo [] s_members = t.FindMembers (
1229 mt, bf & ~BindingFlags.Instance, filter, criteria);
1231 int s_len = s_members.Length;
1232 if (i_len > 0 || s_len > 0)
1233 return new MemberList (i_members, s_members);
1236 return new MemberList (i_members);
1238 return new MemberList (s_members);
1242 return new MemberList (t.FindMembers (mt, bf, filter, criteria));
1247 /// This method is only called from within MemberLookup. It tries to use the member
1248 /// cache if possible and falls back to the normal FindMembers if not. The `used_cache'
1249 /// flag tells the caller whether we used the cache or not. If we used the cache, then
1250 /// our return value will already contain all inherited members and the caller don't need
1251 /// to check base classes and interfaces anymore.
1253 private static MemberList MemberLookup_FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1254 string name, out bool used_cache)
1256 bool not_loaded_corlib = (t.Assembly == CodeGen.AssemblyBuilder);
1259 // We have to take care of arrays specially, because GetType on
1260 // a TypeBuilder array will return a Type, not a TypeBuilder,
1261 // and we can not call FindMembers on this type.
1263 if (t == TypeManager.array_type || t.IsSubclassOf (TypeManager.array_type)) {
1265 return TypeHandle.ArrayType.MemberCache.FindMembers (
1266 mt, bf, name, FilterWithClosure_delegate, null);
1270 // If this is a dynamic type, it's always in the `builder_to_declspace' hash table
1271 // and we can ask the DeclSpace for the MemberCache.
1273 if (t is TypeBuilder) {
1274 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
1275 MemberCache cache = decl.MemberCache;
1278 // If this DeclSpace has a MemberCache, use it.
1281 if (cache != null) {
1283 return cache.FindMembers (
1284 mt, bf, name, FilterWithClosure_delegate, null);
1287 // If there is no MemberCache, we need to use the "normal" FindMembers.
1290 Timer.StartTimer (TimerType.FindMembers);
1291 list = decl.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
1292 FilterWithClosure_delegate, name);
1293 Timer.StopTimer (TimerType.FindMembers);
1300 // This call will always succeed. There is exactly one TypeHandle instance per
1301 // type, TypeHandle.GetTypeHandle() will either return it or create a new one
1302 // if it didn't already exist.
1304 TypeHandle handle = TypeHandle.GetTypeHandle (t);
1307 return handle.MemberCache.FindMembers (mt, bf, name, FilterWithClosure_delegate, null);
1310 public static bool IsBuiltinType (Type t)
1312 if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
1313 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1314 t == char_type || t == short_type || t == decimal_type || t == bool_type ||
1315 t == sbyte_type || t == byte_type || t == ushort_type || t == void_type)
1322 // This is like IsBuiltinType, but lacks decimal_type, we should also clean up
1323 // the pieces in the code where we use IsBuiltinType and special case decimal_type.
1325 public static bool IsCLRType (Type t)
1327 if (t == object_type || t == int32_type || t == uint32_type ||
1328 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1329 t == char_type || t == short_type || t == bool_type ||
1330 t == sbyte_type || t == byte_type || t == ushort_type)
1336 public static bool IsDelegateType (Type t)
1338 if (t.IsSubclassOf (TypeManager.delegate_type))
1344 public static bool IsEnumType (Type t)
1346 if (t == TypeManager.enum_type || t.IsSubclassOf (TypeManager.enum_type))
1351 public static bool IsBuiltinOrEnum (Type t)
1353 if (IsBuiltinType (t))
1363 // Whether a type is unmanaged. This is used by the unsafe code (25.2)
1365 public static bool IsUnmanagedType (Type t)
1367 if (IsBuiltinType (t) && t != TypeManager.string_type)
1376 if (IsValueType (t)){
1377 if (t is TypeBuilder){
1378 TypeContainer tc = LookupTypeContainer (t);
1380 foreach (Field f in tc.Fields){
1381 if (f.FieldBuilder.IsStatic)
1383 if (!IsUnmanagedType (f.FieldBuilder.FieldType))
1387 FieldInfo [] fields = t.GetFields ();
1389 foreach (FieldInfo f in fields){
1392 if (!IsUnmanagedType (f.FieldType))
1402 public static bool IsValueType (Type t)
1404 if (t.IsSubclassOf (TypeManager.value_type) && (t != TypeManager.enum_type))
1410 public static bool IsInterfaceType (Type t)
1412 Interface iface = builder_to_declspace [t] as Interface;
1421 // Checks whether `type' is a subclass or nested child of `parent'.
1423 public static bool IsSubclassOrNestedChildOf (Type type, Type parent)
1426 if ((type == parent) || type.IsSubclassOf (parent))
1429 // Handle nested types.
1430 type = type.DeclaringType;
1431 } while (type != null);
1437 // Checks whether `type' is a nested child of `parent'.
1439 public static bool IsNestedChildOf (Type type, Type parent)
1444 type = type.DeclaringType;
1445 while (type != null) {
1449 type = type.DeclaringType;
1456 // Do the right thing when returning the element type of an
1457 // array type based on whether we are compiling corlib or not
1459 public static Type GetElementType (Type t)
1461 if (RootContext.StdLib)
1462 return t.GetElementType ();
1464 return TypeToCoreType (t.GetElementType ());
1468 /// Returns the User Defined Types
1470 public static ArrayList UserTypes {
1476 public static Hashtable TypeContainers {
1478 return typecontainers;
1482 static Hashtable attr_to_allowmult;
1484 public static void RegisterAttributeAllowMultiple (Type attr_type, bool allow)
1486 if (attr_to_allowmult == null)
1487 attr_to_allowmult = new PtrHashtable ();
1489 if (attr_to_allowmult.Contains (attr_type))
1492 attr_to_allowmult.Add (attr_type, allow);
1496 public static bool AreMultipleAllowed (Type attr_type)
1498 if (!(attr_type is TypeBuilder)) {
1499 System.Attribute [] attrs = System.Attribute.GetCustomAttributes (attr_type);
1501 foreach (System.Attribute tmp in attrs)
1502 if (tmp is AttributeUsageAttribute) {
1503 return ((AttributeUsageAttribute) tmp).AllowMultiple;
1509 if (attr_to_allowmult == null)
1512 return (bool) attr_to_allowmult [attr_type];
1515 static Hashtable builder_to_constant;
1517 public static void RegisterConstant (FieldBuilder fb, Const c)
1519 if (builder_to_constant == null)
1520 builder_to_constant = new PtrHashtable ();
1522 if (builder_to_constant.Contains (fb))
1525 builder_to_constant.Add (fb, c);
1528 public static Const LookupConstant (FieldBuilder fb)
1530 if (builder_to_constant == null)
1533 return (Const) builder_to_constant [fb];
1537 /// Gigantic work around for missing features in System.Reflection.Emit follows.
1541 /// Since System.Reflection.Emit can not return MethodBase.GetParameters
1542 /// for anything which is dynamic, and we need this in a number of places,
1543 /// we register this information here, and use it afterwards.
1545 static public bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] args)
1550 method_arguments.Add (mb, args);
1551 method_internal_params.Add (mb, ip);
1556 static public InternalParameters LookupParametersByBuilder (MethodBase mb)
1558 if (! (mb is ConstructorBuilder || mb is MethodBuilder))
1561 if (method_internal_params.Contains (mb))
1562 return (InternalParameters) method_internal_params [mb];
1564 throw new Exception ("Argument for Method not registered" + mb);
1568 /// Returns the argument types for a method based on its methodbase
1570 /// For dynamic methods, we use the compiler provided types, for
1571 /// methods from existing assemblies we load them from GetParameters,
1572 /// and insert them into the cache
1574 static public Type [] GetArgumentTypes (MethodBase mb)
1576 if (method_arguments.Contains (mb))
1577 return (Type []) method_arguments [mb];
1579 ParameterInfo [] pi = mb.GetParameters ();
1581 Type [] types = new Type [c];
1583 for (int i = 0; i < c; i++)
1584 types [i] = pi [i].ParameterType;
1586 method_arguments.Add (mb, types);
1592 /// Returns the argument types for an indexer based on its PropertyInfo
1594 /// For dynamic indexers, we use the compiler provided types, for
1595 /// indexers from existing assemblies we load them from GetParameters,
1596 /// and insert them into the cache
1598 static public Type [] GetArgumentTypes (PropertyInfo indexer)
1600 if (indexer_arguments.Contains (indexer))
1601 return (Type []) indexer_arguments [indexer];
1602 else if (indexer is PropertyBuilder)
1603 // If we're a PropertyBuilder and not in the
1604 // `indexer_arguments' hash, then we're a property and
1608 ParameterInfo [] pi = indexer.GetIndexParameters ();
1609 // Property, not an indexer.
1613 Type [] types = new Type [c];
1615 for (int i = 0; i < c; i++)
1616 types [i] = pi [i].ParameterType;
1618 indexer_arguments.Add (indexer, types);
1624 // This is a workaround the fact that GetValue is not
1625 // supported for dynamic types
1627 static Hashtable fields = new Hashtable ();
1628 static public bool RegisterFieldValue (FieldBuilder fb, object value)
1630 if (fields.Contains (fb))
1633 fields.Add (fb, value);
1638 static public object GetValue (FieldBuilder fb)
1643 static Hashtable fieldbuilders_to_fields = new Hashtable ();
1644 static public bool RegisterFieldBase (FieldBuilder fb, FieldBase f)
1646 if (fieldbuilders_to_fields.Contains (fb))
1649 fieldbuilders_to_fields.Add (fb, f);
1654 // The return value can be null; This will be the case for
1655 // auxiliary FieldBuilders created by the compiler that have no
1656 // real field being declared on the source code
1658 static public FieldBase GetField (FieldInfo fb)
1660 return (FieldBase) fieldbuilders_to_fields [fb];
1663 static Hashtable events;
1665 static public bool RegisterEvent (MyEventBuilder eb, MethodBase add, MethodBase remove)
1668 events = new Hashtable ();
1670 if (events.Contains (eb))
1673 events.Add (eb, new Pair (add, remove));
1678 static public MethodInfo GetAddMethod (EventInfo ei)
1680 if (ei is MyEventBuilder) {
1681 Pair pair = (Pair) events [ei];
1683 return (MethodInfo) pair.First;
1685 return ei.GetAddMethod ();
1688 static public MethodInfo GetRemoveMethod (EventInfo ei)
1690 if (ei is MyEventBuilder) {
1691 Pair pair = (Pair) events [ei];
1693 return (MethodInfo) pair.Second;
1695 return ei.GetRemoveMethod ();
1698 static Hashtable priv_fields_events;
1700 static public bool RegisterPrivateFieldOfEvent (EventInfo einfo, FieldBuilder builder)
1702 if (priv_fields_events == null)
1703 priv_fields_events = new Hashtable ();
1705 if (priv_fields_events.Contains (einfo))
1708 priv_fields_events.Add (einfo, builder);
1713 static public MemberInfo GetPrivateFieldOfEvent (EventInfo ei)
1715 if (priv_fields_events == null)
1718 return (MemberInfo) priv_fields_events [ei];
1721 static Hashtable properties;
1723 static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set)
1725 if (properties == null)
1726 properties = new Hashtable ();
1728 if (properties.Contains (pb))
1731 properties.Add (pb, new Pair (get, set));
1736 static public bool RegisterIndexer (PropertyBuilder pb, MethodBase get,
1737 MethodBase set, Type[] args)
1739 if (!RegisterProperty (pb, get,set))
1742 indexer_arguments.Add (pb, args);
1748 /// Given an array of interface types, expand and eliminate repeated ocurrences
1749 /// of an interface.
1753 /// This expands in context like: IA; IB : IA; IC : IA, IB; the interface "IC" to
1756 public static Type [] ExpandInterfaces (Type [] base_interfaces)
1758 ArrayList new_ifaces = new ArrayList ();
1760 foreach (Type iface in base_interfaces){
1761 if (!new_ifaces.Contains (iface))
1762 new_ifaces.Add (iface);
1764 Type [] implementing = TypeManager.GetInterfaces (iface);
1766 foreach (Type imp in implementing){
1767 if (!new_ifaces.Contains (imp))
1768 new_ifaces.Add (imp);
1771 Type [] ret = new Type [new_ifaces.Count];
1772 new_ifaces.CopyTo (ret, 0);
1777 /// This function returns the interfaces in the type `t'. Works with
1778 /// both types and TypeBuilders.
1780 public static Type [] GetInterfaces (Type t)
1783 // The reason for catching the Array case is that Reflection.Emit
1784 // will not return a TypeBuilder for Array types of TypeBuilder types,
1785 // but will still throw an exception if we try to call GetInterfaces
1788 // Since the array interfaces are always constant, we return those for
1793 t = TypeManager.array_type;
1795 if (t is TypeBuilder){
1796 Type [] parent_ifaces;
1798 if (t.BaseType == null)
1799 parent_ifaces = NoTypes;
1801 parent_ifaces = GetInterfaces (t.BaseType);
1802 Type [] type_ifaces = (Type []) builder_to_ifaces [t];
1803 if (type_ifaces == null)
1804 type_ifaces = NoTypes;
1806 int parent_count = parent_ifaces.Length;
1807 Type [] result = new Type [parent_count + type_ifaces.Length];
1808 parent_ifaces.CopyTo (result, 0);
1809 type_ifaces.CopyTo (result, parent_count);
1813 return t.GetInterfaces ();
1817 /// The following is used to check if a given type implements an interface.
1818 /// The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
1820 public static bool ImplementsInterface (Type t, Type iface)
1825 // FIXME OPTIMIZATION:
1826 // as soon as we hit a non-TypeBuiler in the interface
1827 // chain, we could return, as the `Type.GetInterfaces'
1828 // will return all the interfaces implement by the type
1832 interfaces = GetInterfaces (t);
1834 if (interfaces != null){
1835 foreach (Type i in interfaces){
1842 } while (t != null);
1847 static NumberFormatInfo nf_provider = CultureInfo.CurrentCulture.NumberFormat;
1849 // This is a custom version of Convert.ChangeType() which works
1850 // with the TypeBuilder defined types when compiling corlib.
1851 public static object ChangeType (object value, Type conversionType, out bool error)
1853 IConvertible convert_value = value as IConvertible;
1855 if (convert_value == null){
1861 // We must use Type.Equals() here since `conversionType' is
1862 // the TypeBuilder created version of a system type and not
1863 // the system type itself. You cannot use Type.GetTypeCode()
1864 // on such a type - it'd always return TypeCode.Object.
1868 if (conversionType.Equals (typeof (Boolean)))
1869 return (object)(convert_value.ToBoolean (nf_provider));
1870 else if (conversionType.Equals (typeof (Byte)))
1871 return (object)(convert_value.ToByte (nf_provider));
1872 else if (conversionType.Equals (typeof (Char)))
1873 return (object)(convert_value.ToChar (nf_provider));
1874 else if (conversionType.Equals (typeof (DateTime)))
1875 return (object)(convert_value.ToDateTime (nf_provider));
1876 else if (conversionType.Equals (typeof (Decimal)))
1877 return (object)(convert_value.ToDecimal (nf_provider));
1878 else if (conversionType.Equals (typeof (Double)))
1879 return (object)(convert_value.ToDouble (nf_provider));
1880 else if (conversionType.Equals (typeof (Int16)))
1881 return (object)(convert_value.ToInt16 (nf_provider));
1882 else if (conversionType.Equals (typeof (Int32)))
1883 return (object)(convert_value.ToInt32 (nf_provider));
1884 else if (conversionType.Equals (typeof (Int64)))
1885 return (object)(convert_value.ToInt64 (nf_provider));
1886 else if (conversionType.Equals (typeof (SByte)))
1887 return (object)(convert_value.ToSByte (nf_provider));
1888 else if (conversionType.Equals (typeof (Single)))
1889 return (object)(convert_value.ToSingle (nf_provider));
1890 else if (conversionType.Equals (typeof (String)))
1891 return (object)(convert_value.ToString (nf_provider));
1892 else if (conversionType.Equals (typeof (UInt16)))
1893 return (object)(convert_value.ToUInt16 (nf_provider));
1894 else if (conversionType.Equals (typeof (UInt32)))
1895 return (object)(convert_value.ToUInt32 (nf_provider));
1896 else if (conversionType.Equals (typeof (UInt64)))
1897 return (object)(convert_value.ToUInt64 (nf_provider));
1898 else if (conversionType.Equals (typeof (Object)))
1899 return (object)(value);
1909 // This is needed, because enumerations from assemblies
1910 // do not report their underlyingtype, but they report
1913 public static Type EnumToUnderlying (Type t)
1915 if (t == TypeManager.enum_type)
1918 t = t.UnderlyingSystemType;
1919 if (!TypeManager.IsEnumType (t))
1922 if (t is TypeBuilder) {
1923 // slow path needed to compile corlib
1924 if (t == TypeManager.bool_type ||
1925 t == TypeManager.byte_type ||
1926 t == TypeManager.sbyte_type ||
1927 t == TypeManager.char_type ||
1928 t == TypeManager.short_type ||
1929 t == TypeManager.ushort_type ||
1930 t == TypeManager.int32_type ||
1931 t == TypeManager.uint32_type ||
1932 t == TypeManager.int64_type ||
1933 t == TypeManager.uint64_type)
1935 throw new Exception ("Unhandled typecode in enum " + " from " + t.AssemblyQualifiedName);
1937 TypeCode tc = Type.GetTypeCode (t);
1940 case TypeCode.Boolean:
1941 return TypeManager.bool_type;
1943 return TypeManager.byte_type;
1944 case TypeCode.SByte:
1945 return TypeManager.sbyte_type;
1947 return TypeManager.char_type;
1948 case TypeCode.Int16:
1949 return TypeManager.short_type;
1950 case TypeCode.UInt16:
1951 return TypeManager.ushort_type;
1952 case TypeCode.Int32:
1953 return TypeManager.int32_type;
1954 case TypeCode.UInt32:
1955 return TypeManager.uint32_type;
1956 case TypeCode.Int64:
1957 return TypeManager.int64_type;
1958 case TypeCode.UInt64:
1959 return TypeManager.uint64_type;
1961 throw new Exception ("Unhandled typecode in enum " + tc + " from " + t.AssemblyQualifiedName);
1965 // When compiling corlib and called with one of the core types, return
1966 // the corresponding typebuilder for that type.
1968 public static Type TypeToCoreType (Type t)
1970 if (RootContext.StdLib || (t is TypeBuilder))
1973 TypeCode tc = Type.GetTypeCode (t);
1976 case TypeCode.Boolean:
1977 return TypeManager.bool_type;
1979 return TypeManager.byte_type;
1980 case TypeCode.SByte:
1981 return TypeManager.sbyte_type;
1983 return TypeManager.char_type;
1984 case TypeCode.Int16:
1985 return TypeManager.short_type;
1986 case TypeCode.UInt16:
1987 return TypeManager.ushort_type;
1988 case TypeCode.Int32:
1989 return TypeManager.int32_type;
1990 case TypeCode.UInt32:
1991 return TypeManager.uint32_type;
1992 case TypeCode.Int64:
1993 return TypeManager.int64_type;
1994 case TypeCode.UInt64:
1995 return TypeManager.uint64_type;
1996 case TypeCode.Single:
1997 return TypeManager.float_type;
1998 case TypeCode.Double:
1999 return TypeManager.double_type;
2000 case TypeCode.String:
2001 return TypeManager.string_type;
2003 if (t == typeof (void))
2004 return TypeManager.void_type;
2005 if (t == typeof (object))
2006 return TypeManager.object_type;
2007 if (t == typeof (System.Type))
2008 return TypeManager.type_type;
2014 /// Utility function that can be used to probe whether a type
2015 /// is managed or not.
2017 public static bool VerifyUnManaged (Type t, Location loc)
2019 if (t.IsValueType || t.IsPointer){
2021 // FIXME: this is more complex, we actually need to
2022 // make sure that the type does not contain any
2028 if (!RootContext.StdLib && (t == TypeManager.decimal_type))
2029 // We need this explicit check here to make it work when
2030 // compiling corlib.
2035 "Cannot take the address or size of a variable of a managed type ('" +
2036 CSharpName (t) + "')");
2041 /// Returns the name of the indexer in a given type.
2044 /// The default is not always `Item'. The user can change this behaviour by
2045 /// using the DefaultMemberAttribute in the class.
2047 /// For example, the String class indexer is named `Chars' not `Item'
2049 public static string IndexerPropertyName (Type t)
2051 if (t is TypeBuilder) {
2052 if (t.IsInterface) {
2053 Interface i = LookupInterface (t);
2055 if ((i == null) || (i.IndexerName == null))
2058 return i.IndexerName;
2060 TypeContainer tc = LookupTypeContainer (t);
2062 if ((tc == null) || (tc.IndexerName == null))
2065 return tc.IndexerName;
2069 System.Attribute attr = System.Attribute.GetCustomAttribute (
2070 t, TypeManager.default_member_type);
2072 DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
2073 return dma.MemberName;
2079 public static void MakePinned (LocalBuilder builder)
2082 // FIXME: Flag the "LocalBuilder" type as being
2083 // pinned. Figure out API.
2089 // Returns whether the array of memberinfos contains the given method
2091 public static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method)
2093 Type [] new_args = TypeManager.GetArgumentTypes (new_method);
2095 foreach (MethodBase method in array) {
2096 if (method.Name != new_method.Name)
2099 if (method is MethodInfo && new_method is MethodInfo)
2100 if (((MethodInfo) method).ReturnType != ((MethodInfo) new_method).ReturnType)
2104 Type [] old_args = TypeManager.GetArgumentTypes (method);
2105 int old_count = old_args.Length;
2108 if (new_args.Length != old_count)
2111 for (i = 0; i < old_count; i++){
2112 if (old_args [i] != new_args [i])
2125 // We copy methods from `new_members' into `target_list' if the signature
2126 // for the method from in the new list does not exist in the target_list
2128 // The name is assumed to be the same.
2130 public static ArrayList CopyNewMethods (ArrayList target_list, MemberList new_members)
2132 if (target_list == null){
2133 target_list = new ArrayList ();
2135 foreach (MemberInfo mi in new_members){
2136 if (mi is MethodBase)
2137 target_list.Add (mi);
2142 MemberInfo [] target_array = new MemberInfo [target_list.Count];
2143 target_list.CopyTo (target_array, 0);
2145 foreach (MemberInfo mi in new_members){
2146 MethodBase new_method = (MethodBase) mi;
2148 if (!ArrayContainsMethod (target_array, new_method))
2149 target_list.Add (new_method);
2155 public enum MethodFlags {
2157 IsObsoleteError = 1 << 1,
2158 ShouldIgnore = 1 << 2
2162 // Returns the TypeManager.MethodFlags for this method.
2163 // This emits an error 619 / warning 618 if the method is obsolete.
2164 // In the former case, TypeManager.MethodFlags.IsObsoleteError is returned.
2166 static public MethodFlags GetMethodFlags (MethodBase mb, Location loc)
2168 MethodFlags flags = 0;
2170 if (mb.DeclaringType is TypeBuilder){
2171 MethodData method = (MethodData) builder_to_method [mb];
2172 if (method == null) {
2173 // FIXME: implement Obsolete attribute on Property,
2174 // Indexer and Event.
2178 return method.GetMethodFlags (loc);
2181 object [] attrs = mb.GetCustomAttributes (true);
2182 foreach (object ta in attrs){
2183 if (!(ta is System.Attribute)){
2184 Console.WriteLine ("Unknown type in GetMethodFlags: " + ta);
2187 System.Attribute a = (System.Attribute) ta;
2188 if (a.TypeId == TypeManager.obsolete_attribute_type){
2189 ObsoleteAttribute oa = (ObsoleteAttribute) a;
2191 string method_desc = TypeManager.CSharpSignature (mb);
2194 Report.Error (619, loc, "Method `" + method_desc +
2195 "' is obsolete: `" + oa.Message + "'");
2196 return MethodFlags.IsObsoleteError;
2198 Report.Warning (618, loc, "Method `" + method_desc +
2199 "' is obsolete: `" + oa.Message + "'");
2201 flags |= MethodFlags.IsObsolete;
2207 // Skip over conditional code.
2209 if (a.TypeId == TypeManager.conditional_attribute_type){
2210 ConditionalAttribute ca = (ConditionalAttribute) a;
2212 if (RootContext.AllDefines [ca.ConditionString] == null)
2213 flags |= MethodFlags.ShouldIgnore;
2220 #region MemberLookup implementation
2223 // Name of the member
2225 static string closure_name;
2228 // Whether we allow private members in the result (since FindMembers
2229 // uses NonPublic for both protected and private), we need to distinguish.
2231 static bool closure_private_ok;
2234 // Who is invoking us and which type is being queried currently.
2236 static Type closure_invocation_type;
2237 static Type closure_queried_type;
2238 static Type closure_qualifier_type;
2241 // The assembly that defines the type is that is calling us
2243 static Assembly closure_invocation_assembly;
2245 static internal bool FilterNone (MemberInfo m, object filter_criteria)
2251 // This filter filters by name + whether it is ok to include private
2252 // members in the search
2254 static internal bool FilterWithClosure (MemberInfo m, object filter_criteria)
2257 // Hack: we know that the filter criteria will always be in the `closure'
2261 if ((filter_criteria != null) && (m.Name != (string) filter_criteria))
2264 if (((closure_qualifier_type == null) || (closure_qualifier_type == closure_invocation_type)) &&
2265 (m.DeclaringType == closure_invocation_type))
2269 // Ugly: we need to find out the type of `m', and depending
2270 // on this, tell whether we accept or not
2272 if (m is MethodBase){
2273 MethodBase mb = (MethodBase) m;
2274 MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
2276 if (ma == MethodAttributes.Private)
2277 return closure_private_ok || (closure_invocation_type == m.DeclaringType) ||
2278 IsNestedChildOf (closure_invocation_type, m.DeclaringType);
2281 // FamAndAssem requires that we not only derivate, but we are on the
2284 if (ma == MethodAttributes.FamANDAssem){
2285 if (closure_invocation_assembly != mb.DeclaringType.Assembly)
2289 // Assembly and FamORAssem succeed if we're in the same assembly.
2290 if ((ma == MethodAttributes.Assembly) || (ma == MethodAttributes.FamORAssem)){
2291 if (closure_invocation_assembly == mb.DeclaringType.Assembly)
2295 // We already know that we aren't in the same assembly.
2296 if (ma == MethodAttributes.Assembly)
2299 // Family and FamANDAssem require that we derive.
2300 if ((ma == MethodAttributes.Family) || (ma == MethodAttributes.FamANDAssem)){
2301 if (closure_invocation_type == null)
2304 if (!IsSubclassOrNestedChildOf (closure_invocation_type, mb.DeclaringType))
2307 // Although a derived class can access protected members of its base class
2308 // it cannot do so through an instance of the base class (CS1540).
2309 if (!mb.IsStatic && (closure_invocation_type != closure_qualifier_type) &&
2310 (closure_qualifier_type != null) &&
2311 closure_invocation_type.IsSubclassOf (closure_qualifier_type))
2321 if (m is FieldInfo){
2322 FieldInfo fi = (FieldInfo) m;
2323 FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask;
2325 if (fa == FieldAttributes.Private)
2326 return closure_private_ok || (closure_invocation_type == m.DeclaringType) ||
2327 IsNestedChildOf (closure_invocation_type, m.DeclaringType);
2330 // FamAndAssem requires that we not only derivate, but we are on the
2333 if (fa == FieldAttributes.FamANDAssem){
2334 if (closure_invocation_assembly != fi.DeclaringType.Assembly)
2338 // Assembly and FamORAssem succeed if we're in the same assembly.
2339 if ((fa == FieldAttributes.Assembly) || (fa == FieldAttributes.FamORAssem)){
2340 if (closure_invocation_assembly == fi.DeclaringType.Assembly)
2344 // We already know that we aren't in the same assembly.
2345 if (fa == FieldAttributes.Assembly)
2348 // Family and FamANDAssem require that we derive.
2349 if ((fa == FieldAttributes.Family) || (fa == FieldAttributes.FamANDAssem)){
2350 if (closure_invocation_type == null)
2353 if (!IsSubclassOrNestedChildOf (closure_invocation_type, fi.DeclaringType))
2356 // Although a derived class can access protected members of its base class
2357 // it cannot do so through an instance of the base class (CS1540).
2358 if (!fi.IsStatic && (closure_invocation_type != closure_qualifier_type) &&
2359 (closure_qualifier_type != null) &&
2360 closure_invocation_type.IsSubclassOf (closure_qualifier_type))
2371 // EventInfos and PropertyInfos, return true because they lack permission
2372 // informaiton, so we need to check later on the methods.
2377 static MemberFilter FilterWithClosure_delegate = new MemberFilter (FilterWithClosure);
2378 static MemberFilter FilterNone_delegate = new MemberFilter (FilterNone);
2381 // Looks up a member called `name' in the `queried_type'. This lookup
2382 // is done by code that is contained in the definition for `invocation_type'
2383 // through a qualifier of type `qualifier_type' (or null if there is no qualifier).
2385 // `invocation_type' is used to check whether we're allowed to access the requested
2386 // member wrt its protection level.
2388 // When called from MemberAccess, `qualifier_type' is the type which is used to access
2389 // the requested member (`class B { A a = new A (); a.foo = 5; }'; here invocation_type
2390 // is B and qualifier_type is A). This is used to do the CS1540 check.
2392 // When resolving a SimpleName, `qualifier_type' is null.
2394 // The `qualifier_type' is used for the CS1540 check; it's normally either null or
2395 // the same than `queried_type' - except when we're being called from BaseAccess;
2396 // in this case, `invocation_type' is the current type and `queried_type' the base
2397 // type, so this'd normally trigger a CS1540.
2399 // The binding flags are `bf' and the kind of members being looked up are `mt'
2401 // The return value always includes private members which code in `invocation_type'
2402 // is allowed to access (using the specified `qualifier_type' if given); only use
2403 // BindingFlags.NonPublic to bypass the permission check.
2405 // Returns an array of a single element for everything but Methods/Constructors
2406 // that might return multiple matches.
2408 public static MemberInfo [] MemberLookup (Type invocation_type, Type qualifier_type,
2409 Type queried_type, MemberTypes mt,
2410 BindingFlags original_bf, string name)
2412 Timer.StartTimer (TimerType.MemberLookup);
2414 MemberInfo[] retval = RealMemberLookup (invocation_type, qualifier_type,
2415 queried_type, mt, original_bf, name);
2417 Timer.StopTimer (TimerType.MemberLookup);
2422 static MemberInfo [] RealMemberLookup (Type invocation_type, Type qualifier_type,
2423 Type queried_type, MemberTypes mt,
2424 BindingFlags original_bf, string name)
2426 BindingFlags bf = original_bf;
2428 ArrayList method_list = null;
2429 Type current_type = queried_type;
2430 bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0;
2431 bool skip_iface_check = true, used_cache = false;
2432 bool always_ok_flag = false;
2434 closure_name = name;
2435 closure_invocation_type = invocation_type;
2436 closure_invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
2437 closure_qualifier_type = qualifier_type;
2440 // If we are a nested class, we always have access to our container
2443 if (invocation_type != null){
2444 string invocation_name = invocation_type.FullName;
2445 if (invocation_name.IndexOf ('+') != -1){
2446 string container = queried_type.FullName + "+";
2447 int container_length = container.Length;
2449 if (invocation_name.Length > container_length){
2450 string shared = invocation_name.Substring (0, container_length);
2452 if (shared == container)
2453 always_ok_flag = true;
2462 // `NonPublic' is lame, because it includes both protected and
2463 // private methods, so we need to control this behavior by
2464 // explicitly tracking if a private method is ok or not.
2466 // The possible cases are:
2467 // public, private and protected (internal does not come into the
2470 if ((invocation_type != null) &&
2471 ((invocation_type == current_type) ||
2472 IsNestedChildOf (invocation_type, current_type)) ||
2474 bf = original_bf | BindingFlags.NonPublic;
2478 closure_private_ok = (original_bf & BindingFlags.NonPublic) != 0;
2479 closure_queried_type = current_type;
2481 Timer.StopTimer (TimerType.MemberLookup);
2483 list = MemberLookup_FindMembers (current_type, mt, bf, name, out used_cache);
2485 Timer.StartTimer (TimerType.MemberLookup);
2488 // When queried for an interface type, the cache will automatically check all
2489 // inherited members, so we don't need to do this here. However, this only
2490 // works if we already used the cache in the first iteration of this loop.
2492 // If we used the cache in any further iteration, we can still terminate the
2493 // loop since the cache always looks in all parent classes.
2499 skip_iface_check = false;
2501 if (current_type == TypeManager.object_type)
2504 current_type = current_type.BaseType;
2507 // This happens with interfaces, they have a null
2508 // basetype. Look members up in the Object class.
2510 if (current_type == null)
2511 current_type = TypeManager.object_type;
2514 if (list.Count == 0)
2518 // Events and types are returned by both `static' and `instance'
2519 // searches, which means that our above FindMembers will
2520 // return two copies of the same.
2522 if (list.Count == 1 && !(list [0] is MethodBase)){
2523 return (MemberInfo []) list;
2527 // Multiple properties: we query those just to find out the indexer
2530 if (list [0] is PropertyInfo)
2531 return (MemberInfo []) list;
2534 // We found an event: the cache lookup returns both the event and
2535 // its private field.
2537 if (list [0] is EventInfo) {
2538 if ((list.Count == 2) && (list [1] is FieldInfo))
2539 return new MemberInfo [] { list [0] };
2546 // We found methods, turn the search into "method scan"
2550 method_list = CopyNewMethods (method_list, list);
2551 mt &= (MemberTypes.Method | MemberTypes.Constructor);
2552 } while (searching);
2554 if (method_list != null && method_list.Count > 0)
2555 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
2558 // This happens if we already used the cache in the first iteration, in this case
2559 // the cache already looked in all interfaces.
2561 if (skip_iface_check)
2565 // Interfaces do not list members they inherit, so we have to
2568 if (!queried_type.IsInterface)
2571 if (queried_type.IsArray)
2572 queried_type = TypeManager.array_type;
2574 Type [] ifaces = GetInterfaces (queried_type);
2578 foreach (Type itype in ifaces){
2581 x = MemberLookup (null, null, itype, mt, bf, name);
2590 // This is used to extract properties and event declarations from a type
2592 static MemberInfo [] SpecialContainerLookup (Type t, bool is_static)
2594 BindingFlags bf = BindingFlags.DeclaredOnly | (is_static ? BindingFlags.Static : BindingFlags.Instance);
2596 bf |= BindingFlags.Public | BindingFlags.NonPublic;
2598 if (t is TypeBuilder) {
2599 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
2601 return (MemberInfo []) decl.FindMembers (
2602 MemberTypes.Property | MemberTypes.Event,
2603 bf, FilterNone_delegate, null);
2605 return t.FindMembers (MemberTypes.Property | MemberTypes.Event,
2606 bf, FilterNone_delegate, null);
2611 public static bool IsSpecialMethod (MethodBase mb)
2613 Type t = mb.DeclaringType;
2615 MemberInfo [] matches = TypeManager.SpecialContainerLookup (t, mb.IsStatic);
2616 if (matches == null)
2619 foreach (MemberInfo mi in matches){
2620 if (mi is PropertyBuilder){
2621 Pair p = (Pair) properties [mi];
2623 if (p.First == mb || p.Second == mb)
2625 } else if (mi is PropertyInfo){
2626 MethodInfo [] methods = ((PropertyInfo) mi).GetAccessors (true);
2628 foreach (MethodInfo m in methods){
2632 } else if (mi is MyEventBuilder){
2633 Pair p = (Pair) events [mi];
2635 if (p.First == mb || p.Second == mb)
2637 } else if (mi is EventInfo){
2638 EventInfo ei = ((EventInfo) mi);
2640 if (ei.GetAddMethod (true) == mb)
2643 if (ei.GetRemoveMethod (true) == mb)
2646 if (ei.GetRaiseMethod (true) == mb)
2652 // Now check if it is an operator method
2656 if (s.StartsWith ("op_")){
2657 foreach (string name in Unary.oper_names){
2662 foreach (string name in Binary.oper_names){
2676 /// There is exactly one instance of this class per type.
2678 public sealed class TypeHandle : IMemberContainer {
2679 public readonly TypeHandle BaseType;
2681 readonly int id = ++next_id;
2682 static int next_id = 0;
2685 /// Lookup a TypeHandle instance for the given type. If the type doesn't have
2686 /// a TypeHandle yet, a new instance of it is created. This static method
2687 /// ensures that we'll only have one TypeHandle instance per type.
2689 public static TypeHandle GetTypeHandle (Type t)
2691 TypeHandle handle = (TypeHandle) type_hash [t];
2695 handle = new TypeHandle (t);
2696 type_hash.Add (t, handle);
2701 /// Returns the TypeHandle for TypeManager.object_type.
2703 public static IMemberContainer ObjectType {
2705 if (object_type != null)
2708 object_type = GetTypeHandle (TypeManager.object_type);
2715 /// Returns the TypeHandle for TypeManager.array_type.
2717 public static IMemberContainer ArrayType {
2719 if (array_type != null)
2722 array_type = GetTypeHandle (TypeManager.array_type);
2728 private static PtrHashtable type_hash = new PtrHashtable ();
2730 private static TypeHandle object_type = null;
2731 private static TypeHandle array_type = null;
2734 private bool is_interface;
2735 private MemberCache member_cache;
2737 private TypeHandle (Type type)
2740 if (type.BaseType != null)
2741 BaseType = GetTypeHandle (type.BaseType);
2742 this.is_interface = type.IsInterface;
2743 this.member_cache = new MemberCache (this);
2746 // IMemberContainer methods
2748 public string Name {
2750 return type.FullName;
2760 public IMemberContainer Parent {
2766 public bool IsInterface {
2768 return is_interface;
2772 public MemberList GetMembers (MemberTypes mt, BindingFlags bf)
2774 MemberInfo [] members;
2775 if (mt == MemberTypes.Event)
2776 members = type.GetEvents (bf | BindingFlags.DeclaredOnly);
2778 members = type.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
2780 Array.Reverse (members);
2782 return new MemberList (members);
2785 // IMemberFinder methods
2787 public MemberList FindMembers (MemberTypes mt, BindingFlags bf, string name,
2788 MemberFilter filter, object criteria)
2790 return member_cache.FindMembers (mt, bf, name, filter, criteria);
2793 public MemberCache MemberCache {
2795 return member_cache;
2799 public override string ToString ()
2801 if (BaseType != null)
2802 return "TypeHandle (" + id + "," + Name + " : " + BaseType + ")";
2804 return "TypeHandle (" + id + "," + Name + ")";