2 // typemanager.cs: C# type manager
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 // Ravi Pratap (ravi@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
10 // Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
11 // Copyright 2003-2008 Novell, Inc.
16 using System
.Globalization
;
17 using System
.Collections
.Generic
;
18 using System
.Reflection
;
19 using System
.Reflection
.Emit
;
21 using System
.Runtime
.CompilerServices
;
22 using System
.Diagnostics
;
25 namespace Mono
.CSharp
{
27 partial class TypeManager
{
29 // A list of core types that the compiler requires or uses
31 static public PredefinedTypeSpec object_type
;
32 static public PredefinedTypeSpec value_type
;
33 static public PredefinedTypeSpec string_type
;
34 static public PredefinedTypeSpec int32_type
;
35 static public PredefinedTypeSpec uint32_type
;
36 static public PredefinedTypeSpec int64_type
;
37 static public PredefinedTypeSpec uint64_type
;
38 static public PredefinedTypeSpec float_type
;
39 static public PredefinedTypeSpec double_type
;
40 static public PredefinedTypeSpec char_type
;
41 static public PredefinedTypeSpec short_type
;
42 static public PredefinedTypeSpec decimal_type
;
43 static public PredefinedTypeSpec bool_type
;
44 static public PredefinedTypeSpec sbyte_type
;
45 static public PredefinedTypeSpec byte_type
;
46 static public PredefinedTypeSpec ushort_type
;
47 static public PredefinedTypeSpec enum_type
;
48 static public PredefinedTypeSpec delegate_type
;
49 static public PredefinedTypeSpec multicast_delegate_type
;
50 static public PredefinedTypeSpec void_type
;
51 static public PredefinedTypeSpec array_type
;
52 static public PredefinedTypeSpec runtime_handle_type
;
53 static public PredefinedTypeSpec type_type
;
54 static public PredefinedTypeSpec ienumerator_type
;
55 static public PredefinedTypeSpec ienumerable_type
;
56 static public PredefinedTypeSpec idisposable_type
;
57 static public PredefinedTypeSpec intptr_type
;
58 static public PredefinedTypeSpec uintptr_type
;
59 static public PredefinedTypeSpec runtime_field_handle_type
;
60 static public PredefinedTypeSpec attribute_type
;
61 static public PredefinedTypeSpec exception_type
;
64 static public TypeSpec null_type
;
65 static public TypeSpec typed_reference_type
;
66 static public TypeSpec arg_iterator_type
;
67 static public TypeSpec mbr_type
;
68 public static TypeSpec runtime_helpers_type
;
69 static public TypeSpec iasyncresult_type
;
70 static public TypeSpec asynccallback_type
;
71 static public TypeSpec runtime_argument_handle_type
;
72 static public TypeSpec void_ptr_type
;
77 static internal TypeSpec isvolatile_type
;
78 static public TypeSpec generic_ilist_type
;
79 static public TypeSpec generic_icollection_type
;
80 static public TypeSpec generic_ienumerator_type
;
81 static public TypeSpec generic_ienumerable_type
;
82 static public TypeSpec generic_nullable_type
;
87 static internal TypeSpec expression_type
;
88 public static TypeSpec parameter_expression_type
;
89 public static TypeSpec fieldinfo_type
;
90 public static TypeSpec methodinfo_type
;
91 public static TypeSpec ctorinfo_type
;
96 public static TypeSpec call_site_type
;
97 public static TypeSpec generic_call_site_type
;
98 public static TypeExpr binder_type
;
99 public static TypeSpec binder_flags
;
102 // Expressions representing the internal types. Used during declaration
105 static public TypeExpr system_object_expr
, system_string_expr
;
106 static public TypeExpr system_boolean_expr
, system_decimal_expr
;
107 static public TypeExpr system_single_expr
, system_double_expr
;
108 static public TypeExpr system_sbyte_expr
, system_byte_expr
;
109 static public TypeExpr system_int16_expr
, system_uint16_expr
;
110 static public TypeExpr system_int32_expr
, system_uint32_expr
;
111 static public TypeExpr system_int64_expr
, system_uint64_expr
;
112 static public TypeExpr system_char_expr
, system_void_expr
;
113 static public TypeExpr system_valuetype_expr
;
114 public static TypeExpr expression_type_expr
;
118 // These methods are called by code generated by the compiler
120 static public FieldSpec string_empty
;
121 static public MethodSpec system_type_get_type_from_handle
;
122 static public MethodSpec bool_movenext_void
;
123 static public MethodSpec void_dispose_void
;
124 static public MethodSpec void_monitor_enter_object
;
125 static public MethodSpec void_monitor_exit_object
;
126 static public MethodSpec void_initializearray_array_fieldhandle
;
127 static public MethodSpec delegate_combine_delegate_delegate
;
128 static public MethodSpec delegate_remove_delegate_delegate
;
129 static public PropertySpec int_get_offset_to_string_data
;
130 static public MethodSpec int_interlocked_compare_exchange
;
131 static public PropertySpec ienumerator_getcurrent
;
132 public static MethodSpec methodbase_get_type_from_handle
;
133 public static MethodSpec methodbase_get_type_from_handle_generic
;
134 public static MethodSpec fieldinfo_get_field_from_handle
;
135 public static MethodSpec fieldinfo_get_field_from_handle_generic
;
136 static public MethodSpec activator_create_instance
;
141 static public MethodSpec void_decimal_ctor_five_args
;
142 static public MethodSpec void_decimal_ctor_int_arg
;
143 public static MethodSpec void_decimal_ctor_long_arg
;
145 static Dictionary
<Assembly
, bool> assembly_internals_vis_attrs
;
148 // These are expressions that represent some of the internal data types, used
151 public static void InitExpressionTypes ()
153 system_object_expr
= new TypeLookupExpression (object_type
);
154 system_string_expr
= new TypeLookupExpression (string_type
);
155 system_boolean_expr
= new TypeLookupExpression (bool_type
);
156 system_decimal_expr
= new TypeLookupExpression (decimal_type
);
157 system_single_expr
= new TypeLookupExpression (float_type
);
158 system_double_expr
= new TypeLookupExpression (double_type
);
159 system_sbyte_expr
= new TypeLookupExpression (sbyte_type
);
160 system_byte_expr
= new TypeLookupExpression (byte_type
);
161 system_int16_expr
= new TypeLookupExpression (short_type
);
162 system_uint16_expr
= new TypeLookupExpression (ushort_type
);
163 system_int32_expr
= new TypeLookupExpression (int32_type
);
164 system_uint32_expr
= new TypeLookupExpression (uint32_type
);
165 system_int64_expr
= new TypeLookupExpression (int64_type
);
166 system_uint64_expr
= new TypeLookupExpression (uint64_type
);
167 system_char_expr
= new TypeLookupExpression (char_type
);
168 system_void_expr
= new TypeLookupExpression (void_type
);
169 system_valuetype_expr
= new TypeLookupExpression (value_type
);
172 static TypeManager ()
177 static public void Reset ()
179 // object_type = null;
181 type_hash
= new DoubleHash ();
182 assembly_internals_vis_attrs
= new Dictionary
<Assembly
, bool> ();
184 // TODO: I am really bored by all this static stuff
185 system_type_get_type_from_handle
=
188 void_monitor_enter_object
=
189 void_monitor_exit_object
=
190 void_initializearray_array_fieldhandle
=
191 int_interlocked_compare_exchange
=
192 methodbase_get_type_from_handle
=
193 methodbase_get_type_from_handle_generic
=
194 fieldinfo_get_field_from_handle
=
195 fieldinfo_get_field_from_handle_generic
=
196 activator_create_instance
=
197 delegate_combine_delegate_delegate
=
198 delegate_remove_delegate_delegate
= null;
200 int_get_offset_to_string_data
=
201 ienumerator_getcurrent
= null;
203 void_decimal_ctor_five_args
=
204 void_decimal_ctor_int_arg
=
205 void_decimal_ctor_long_arg
= null;
210 generic_call_site_type
=
215 typed_reference_type
= arg_iterator_type
= mbr_type
=
216 runtime_helpers_type
= iasyncresult_type
= asynccallback_type
=
217 runtime_argument_handle_type
= void_ptr_type
= isvolatile_type
=
218 generic_ilist_type
= generic_icollection_type
= generic_ienumerator_type
=
219 generic_ienumerable_type
= generic_nullable_type
= expression_type
=
220 parameter_expression_type
= fieldinfo_type
= methodinfo_type
= ctorinfo_type
= null;
222 expression_type_expr
= null;
226 // We use this hash for multiple kinds of constructed types:
228 // (T, "&") Given T, get T &
229 // (T, "*") Given T, get T *
230 // (T, "[]") Given T and a array dimension, get T []
231 // (T, X) Given a type T and a simple name X, get the type T+X
233 // Accessibility tests, if necessary, should be done by the user
235 static DoubleHash type_hash
= new DoubleHash ();
238 // Gets the reference to T version of the Type (T&)
240 public static Type
GetReferenceType (TypeSpec t
)
242 return t
.GetMetaInfo ().MakeByRefType ();
245 public static TypeSpec
GetConstructedType (TypeSpec t
, string dim
)
248 if (type_hash
.Lookup (t
, dim
, out ret
))
249 return (TypeSpec
) ret
;
252 if (dim
.Length
== 1) {
254 ds
= PointerContainer
.MakeType (t
);
255 } else if (dim
[0] == '&') {
256 ds
= ReferenceContainer
.MakeType (t
);
258 throw new NotImplementedException ("net");
260 } else if (dim
.Length
== 2) { // optimizes common "[]"
261 ds
= ArrayContainer
.MakeType (t
);
263 int rank
= dim
.IndexOf (']');
264 if (rank
+ 1 != dim
.Length
)
265 t
= GetConstructedType (t
, dim
.Substring (rank
+ 1));
267 ds
= ArrayContainer
.MakeType (t
, rank
);
270 type_hash
.Insert (t
, dim
, ds
);
275 /// Returns the C# name of a type if possible, or the full type name otherwise
277 static public string CSharpName (TypeSpec t
)
279 return t
.GetSignatureForError ();
282 static public string CSharpName (IList
<TypeSpec
> types
)
284 if (types
.Count
== 0)
287 StringBuilder sb
= new StringBuilder ();
288 for (int i
= 0; i
< types
.Count
; ++i
) {
292 sb
.Append (CSharpName (types
[i
]));
294 return sb
.ToString ();
297 static public string GetFullNameSignature (MemberSpec mi
)
299 return mi
.GetSignatureForError ();
302 static public string CSharpSignature (MemberSpec mb
)
304 return mb
.GetSignatureForError ();
308 // Looks up a type, and aborts if it is not found. This is used
309 // by predefined types required by the compiler
311 public static TypeSpec
CoreLookupType (CompilerContext ctx
, string ns_name
, string name
, MemberKind kind
, bool required
)
313 return CoreLookupType (ctx
, ns_name
, name
, 0, kind
, required
);
316 public static TypeSpec
CoreLookupType (CompilerContext ctx
, string ns_name
, string name
, int arity
, MemberKind kind
, bool required
)
318 Namespace ns
= GlobalRootNamespace
.Instance
.GetNamespace (ns_name
, true);
319 var te
= ns
.Lookup (ctx
, name
, arity
, Location
.Null
);
320 var ts
= te
== null ? null : te
.Type
;
326 ctx
.Report
.Error (518, "The predefined type `{0}.{1}' is not defined or imported",
331 if (ts
.Kind
!= kind
) {
332 ctx
.Report
.Error (520, "The predefined type `{0}.{1}' is not declared correctly",
340 static MemberSpec
GetPredefinedMember (TypeSpec t
, MemberFilter filter
, Location loc
)
342 const BindingRestriction restrictions
= BindingRestriction
.AccessibleOnly
| BindingRestriction
.DeclaredOnly
;
343 var member
= MemberCache
.FindMember (t
, filter
, restrictions
);
348 string method_args
= null;
349 if (filter
.Parameters
!= null)
350 method_args
= filter
.Parameters
.GetSignatureForError ();
352 RootContext
.ToplevelTypes
.Compiler
.Report
.Error (656, loc
, "The compiler required member `{0}.{1}{2}' could not be found or is inaccessible",
353 TypeManager
.CSharpName (t
), filter
.Name
, method_args
);
359 // Returns the ConstructorInfo for "args"
361 public static MethodSpec
GetPredefinedConstructor (TypeSpec t
, Location loc
, params TypeSpec
[] args
)
363 var pc
= ParametersCompiled
.CreateFullyResolved (args
);
364 return GetPredefinedMember (t
, MemberFilter
.Constructor (pc
), loc
) as MethodSpec
;
368 // Returns the method specification for a method named `name' defined
369 // in type `t' which takes arguments of types `args'
371 public static MethodSpec
GetPredefinedMethod (TypeSpec t
, string name
, Location loc
, params TypeSpec
[] args
)
373 var pc
= ParametersCompiled
.CreateFullyResolved (args
);
374 return GetPredefinedMethod (t
, MemberFilter
.Method (name
, 0, pc
, null), loc
);
377 public static MethodSpec
GetPredefinedMethod (TypeSpec t
, MemberFilter filter
, Location loc
)
379 return GetPredefinedMember (t
, filter
, loc
) as MethodSpec
;
382 public static FieldSpec
GetPredefinedField (TypeSpec t
, string name
, Location loc
, TypeSpec type
)
384 return GetPredefinedMember (t
, MemberFilter
.Field (name
, type
), loc
) as FieldSpec
;
387 public static PropertySpec
GetPredefinedProperty (TypeSpec t
, string name
, Location loc
, TypeSpec type
)
389 return GetPredefinedMember (t
, MemberFilter
.Property (name
, type
), loc
) as PropertySpec
;
392 public static IList
<PredefinedTypeSpec
> InitCoreTypes ()
394 var core_types
= new PredefinedTypeSpec
[] {
395 object_type
= new PredefinedTypeSpec (MemberKind
.Class
, "System", "Object"),
396 value_type
= new PredefinedTypeSpec (MemberKind
.Class
, "System", "ValueType"),
397 attribute_type
= new PredefinedTypeSpec (MemberKind
.Class
, "System", "Attribute"),
399 int32_type
= new PredefinedTypeSpec (MemberKind
.Struct
, "System", "Int32"),
400 int64_type
= new PredefinedTypeSpec (MemberKind
.Struct
, "System", "Int64"),
401 uint32_type
= new PredefinedTypeSpec (MemberKind
.Struct
, "System", "UInt32"),
402 uint64_type
= new PredefinedTypeSpec (MemberKind
.Struct
, "System", "UInt64"),
403 byte_type
= new PredefinedTypeSpec (MemberKind
.Struct
, "System", "Byte"),
404 sbyte_type
= new PredefinedTypeSpec (MemberKind
.Struct
, "System", "SByte"),
405 short_type
= new PredefinedTypeSpec (MemberKind
.Struct
, "System", "Int16"),
406 ushort_type
= new PredefinedTypeSpec (MemberKind
.Struct
, "System", "UInt16"),
408 ienumerator_type
= new PredefinedTypeSpec (MemberKind
.Interface
, "System.Collections", "IEnumerator"),
409 ienumerable_type
= new PredefinedTypeSpec (MemberKind
.Interface
, "System.Collections", "IEnumerable"),
410 idisposable_type
= new PredefinedTypeSpec (MemberKind
.Interface
, "System", "IDisposable"),
412 char_type
= new PredefinedTypeSpec (MemberKind
.Struct
, "System", "Char"),
413 string_type
= new PredefinedTypeSpec (MemberKind
.Class
, "System", "String"),
414 float_type
= new PredefinedTypeSpec (MemberKind
.Struct
, "System", "Single"),
415 double_type
= new PredefinedTypeSpec (MemberKind
.Struct
, "System", "Double"),
416 decimal_type
= new PredefinedTypeSpec (MemberKind
.Struct
, "System", "Decimal"),
417 bool_type
= new PredefinedTypeSpec (MemberKind
.Struct
, "System", "Boolean"),
418 intptr_type
= new PredefinedTypeSpec (MemberKind
.Struct
, "System", "IntPtr"),
419 uintptr_type
= new PredefinedTypeSpec (MemberKind
.Struct
, "System", "UIntPtr"),
421 multicast_delegate_type
= new PredefinedTypeSpec (MemberKind
.Class
, "System", "MulticastDelegate"),
422 delegate_type
= new PredefinedTypeSpec (MemberKind
.Class
, "System", "Delegate"),
423 enum_type
= new PredefinedTypeSpec (MemberKind
.Class
, "System", "Enum"),
424 array_type
= new PredefinedTypeSpec (MemberKind
.Class
, "System", "Array"),
425 void_type
= new PredefinedTypeSpec (MemberKind
.Struct
, "System", "Void"),
426 type_type
= new PredefinedTypeSpec (MemberKind
.Class
, "System", "Type"),
427 exception_type
= new PredefinedTypeSpec (MemberKind
.Class
, "System", "Exception"),
428 runtime_field_handle_type
= new PredefinedTypeSpec (MemberKind
.Struct
, "System", "RuntimeFieldHandle"),
429 runtime_handle_type
= new PredefinedTypeSpec (MemberKind
.Struct
, "System", "RuntimeTypeHandle"),
436 /// The types have to be initialized after the initial
437 /// population of the type has happened (for example, to
438 /// bootstrap the corlib.dll
440 public static bool InitCoreTypes (CompilerContext ctx
, IList
<PredefinedTypeSpec
> predefined
)
442 foreach (var p
in predefined
) {
443 var found
= CoreLookupType (ctx
, p
.Namespace
, p
.Name
, p
.Kind
, true);
444 if (found
== null || found
== p
)
447 if (!RootContext
.StdLib
) {
448 var ns
= GlobalRootNamespace
.Instance
.GetNamespace (p
.Namespace
, false);
449 ns
.ReplaceTypeWithPredefined (found
, p
);
451 var tc
= found
.MemberDefinition
as TypeContainer
;
452 tc
.SetPredefinedSpec (p
);
453 p
.SetDefinition (found
);
457 PredefinedAttributes
.Get
.ParamArray
.Initialize (ctx
, false);
458 PredefinedAttributes
.Get
.Out
.Initialize (ctx
, false);
460 return ctx
.Report
.Errors
== 0;
464 // Initializes optional core types
466 public static void InitOptionalCoreTypes (CompilerContext ctx
)
469 // These are only used for compare purposes
471 null_type
= InternalType
.Null
;
473 void_ptr_type
= PointerContainer
.MakeType (void_type
);
476 // Initialize InternalsVisibleTo as the very first optional type. Otherwise we would populate
477 // types cache with incorrect accessiblity when any of optional types is internal.
479 PredefinedAttributes
.Get
.Initialize (ctx
);
481 runtime_argument_handle_type
= CoreLookupType (ctx
, "System", "RuntimeArgumentHandle", MemberKind
.Struct
, false);
482 asynccallback_type
= CoreLookupType (ctx
, "System", "AsyncCallback", MemberKind
.Delegate
, false);
483 iasyncresult_type
= CoreLookupType (ctx
, "System", "IAsyncResult", MemberKind
.Interface
, false);
484 typed_reference_type
= CoreLookupType (ctx
, "System", "TypedReference", MemberKind
.Struct
, false);
485 arg_iterator_type
= CoreLookupType (ctx
, "System", "ArgIterator", MemberKind
.Struct
, false);
486 mbr_type
= CoreLookupType (ctx
, "System", "MarshalByRefObject", MemberKind
.Class
, false);
488 generic_ienumerator_type
= CoreLookupType (ctx
, "System.Collections.Generic", "IEnumerator", 1, MemberKind
.Interface
, false);
489 generic_ilist_type
= CoreLookupType (ctx
, "System.Collections.Generic", "IList", 1, MemberKind
.Interface
, false);
490 generic_icollection_type
= CoreLookupType (ctx
, "System.Collections.Generic", "ICollection", 1, MemberKind
.Interface
, false);
491 generic_ienumerable_type
= CoreLookupType (ctx
, "System.Collections.Generic", "IEnumerable", 1, MemberKind
.Interface
, false);
492 generic_nullable_type
= CoreLookupType (ctx
, "System", "Nullable", 1, MemberKind
.Struct
, false);
495 // Optional types which are used as types and for member lookup
497 runtime_helpers_type
= CoreLookupType (ctx
, "System.Runtime.CompilerServices", "RuntimeHelpers", MemberKind
.Class
, false);
500 // Note: extension_attribute_type is already loaded
501 expression_type
= CoreLookupType (ctx
, "System.Linq.Expressions", "Expression", 1, MemberKind
.Class
, false);
504 public static bool IsBuiltinType (TypeSpec t
)
506 if (t
== object_type
|| t
== string_type
|| t
== int32_type
|| t
== uint32_type
||
507 t
== int64_type
|| t
== uint64_type
|| t
== float_type
|| t
== double_type
||
508 t
== char_type
|| t
== short_type
|| t
== decimal_type
|| t
== bool_type
||
509 t
== sbyte_type
|| t
== byte_type
|| t
== ushort_type
|| t
== void_type
)
516 // This is like IsBuiltinType, but lacks decimal_type, we should also clean up
517 // the pieces in the code where we use IsBuiltinType and special case decimal_type.
519 public static bool IsPrimitiveType (TypeSpec t
)
521 return (t
== int32_type
|| t
== uint32_type
||
522 t
== int64_type
|| t
== uint64_type
|| t
== float_type
|| t
== double_type
||
523 t
== char_type
|| t
== short_type
|| t
== bool_type
||
524 t
== sbyte_type
|| t
== byte_type
|| t
== ushort_type
);
528 public static bool IsDelegateType (TypeSpec t
)
534 // When any element of the type is a dynamic type
536 // This method builds a transformation array for dynamic types
537 // used in places where DynamicAttribute cannot be applied to.
538 // It uses bool flag when type is of dynamic type and each
539 // section always starts with "false" for some reason.
541 // LAMESPEC: This should be part of C# specification !
543 // Example: Func<dynamic, int, dynamic[]>
544 // Transformation: { false, true, false, false, true }
546 public static bool[] HasDynamicTypeUsed (TypeSpec t
)
548 var ac
= t
as ArrayContainer
;
550 if (HasDynamicTypeUsed (ac
.Element
) != null)
551 return new bool[] { false, true }
;
559 if (IsGenericType (t
)) {
560 List
<bool> transform
= null;
561 var targs
= GetTypeArguments (t
);
562 for (int i
= 0; i
< targs
.Length
; ++i
) {
563 var element
= HasDynamicTypeUsed (targs
[i
]);
564 if (element
!= null) {
565 if (transform
== null) {
566 transform
= new List
<bool> ();
567 for (int ii
= 0; ii
<= i
; ++ii
)
568 transform
.Add (false);
571 transform
.AddRange (element
);
572 } else if (transform
!= null) {
573 transform
.Add (false);
577 if (transform
!= null)
578 return transform
.ToArray ();
581 if (object.ReferenceEquals (InternalType
.Dynamic
, t
))
582 return new bool [] { true }
;
588 public static bool IsEnumType (TypeSpec t
)
593 public static bool IsBuiltinOrEnum (TypeSpec t
)
595 if (IsBuiltinType (t
))
605 // Whether a type is unmanaged. This is used by the unsafe code (25.2)
607 public static bool IsUnmanagedType (TypeSpec t
)
609 var ds
= t
.MemberDefinition
as DeclSpace
;
611 return ds
.IsUnmanagedType ();
613 // some builtins that are not unmanaged types
614 if (t
== TypeManager
.object_type
|| t
== TypeManager
.string_type
)
617 if (IsBuiltinOrEnum (t
))
620 // Someone did the work of checking if the ElementType of t is unmanaged. Let's not repeat it.
622 return IsUnmanagedType (GetElementType (t
));
624 if (!IsValueType (t
))
627 if (t
.IsNested
&& t
.DeclaringType
.IsGenericOrParentIsGeneric
)
634 // Null is considered to be a reference type
636 public static bool IsReferenceType (TypeSpec t
)
638 if (t
.IsGenericParameter
)
639 return ((TypeParameterSpec
) t
).IsReferenceType
;
641 return !t
.IsStruct
&& !IsEnumType (t
);
644 public static bool IsValueType (TypeSpec t
)
646 if (t
.IsGenericParameter
)
647 return ((TypeParameterSpec
) t
).IsValueType
;
649 return t
.IsStruct
|| IsEnumType (t
);
652 public static bool IsStruct (TypeSpec t
)
657 public static bool IsSubclassOf (TypeSpec type
, TypeSpec base_type
)
660 if (type
== base_type
)
663 type
= type
.BaseType
;
664 } while (type
!= null);
669 public static bool IsFamilyAccessible (TypeSpec type
, TypeSpec parent
)
671 // TypeParameter tparam = LookupTypeParameter (type);
672 // TypeParameter pparam = LookupTypeParameter (parent);
674 if (type
.Kind
== MemberKind
.TypeParameter
&& parent
.Kind
== MemberKind
.TypeParameter
) { // (tparam != null) && (pparam != null)) {
678 throw new NotImplementedException ("net");
679 // return tparam.IsSubclassOf (parent);
683 if (IsInstantiationOfSameGenericType (type
, parent
))
686 type
= type
.BaseType
;
687 } while (type
!= null);
693 // Checks whether `type' is a subclass or nested child of `base_type'.
695 public static bool IsNestedFamilyAccessible (TypeSpec type
, TypeSpec base_type
)
698 if (IsFamilyAccessible (type
, base_type
))
701 // Handle nested types.
702 type
= type
.DeclaringType
;
703 } while (type
!= null);
709 // Checks whether `type' is a nested child of `parent'.
711 public static bool IsNestedChildOf (TypeSpec type
, TypeSpec parent
)
716 type
= type
.GetDefinition (); // DropGenericTypeArguments (type);
717 parent
= parent
.GetDefinition (); // DropGenericTypeArguments (parent);
719 if (IsEqual (type
, parent
))
722 type
= type
.DeclaringType
;
723 while (type
!= null) {
724 if (IsEqual (type
.GetDefinition (), parent
))
727 type
= type
.DeclaringType
;
733 public static bool IsSpecialType (TypeSpec t
)
735 return t
== arg_iterator_type
|| t
== typed_reference_type
;
739 // Checks whether `invocationAssembly' is same or a friend of the assembly
741 public static bool IsThisOrFriendAssembly (Assembly invocationAssembly
, Assembly assembly
)
743 if (assembly
== null)
744 throw new ArgumentNullException ("assembly");
746 // TODO: This can happen for constants used at assembly level and
747 // predefined members
748 // But there is no way to test for it for now, so it could be abused
750 if (invocationAssembly
== null)
751 invocationAssembly
= CodeGen
.Assembly
.Builder
;
753 if (invocationAssembly
== assembly
)
757 if (assembly_internals_vis_attrs
.TryGetValue (assembly
, out value))
760 object[] attrs
= assembly
.GetCustomAttributes (typeof (InternalsVisibleToAttribute
), false);
761 if (attrs
.Length
== 0) {
762 assembly_internals_vis_attrs
.Add (assembly
, false);
766 bool is_friend
= false;
768 AssemblyName this_name
= CodeGen
.Assembly
.Name
;
769 if (this_name
== null)
772 byte [] this_token
= this_name
.GetPublicKeyToken ();
773 foreach (InternalsVisibleToAttribute attr
in attrs
) {
774 if (attr
.AssemblyName
== null || attr
.AssemblyName
.Length
== 0)
777 AssemblyName aname
= null;
779 aname
= new AssemblyName (attr
.AssemblyName
);
780 } catch (FileLoadException
) {
781 } catch (ArgumentException
) {
784 if (aname
== null || aname
.Name
!= this_name
.Name
)
787 byte [] key_token
= aname
.GetPublicKeyToken ();
788 if (key_token
!= null) {
789 if (this_token
.Length
== 0) {
790 // Same name, but assembly is not strongnamed
791 Error_FriendAccessNameNotMatching (aname
.FullName
, RootContext
.ToplevelTypes
.Compiler
.Report
);
795 if (!CompareKeyTokens (this_token
, key_token
))
803 assembly_internals_vis_attrs
.Add (assembly
, is_friend
);
807 static bool CompareKeyTokens (byte [] token1
, byte [] token2
)
809 for (int i
= 0; i
< token1
.Length
; i
++)
810 if (token1
[i
] != token2
[i
])
816 static void Error_FriendAccessNameNotMatching (string other_name
, Report Report
)
819 "Friend access was granted to `{0}', but the output assembly is named `{1}'. Try adding a reference to `{0}' or change the output assembly name to match it",
820 other_name
, CodeGen
.Assembly
.Name
.FullName
);
823 public static TypeSpec
GetElementType (TypeSpec t
)
825 return ((ElementTypeSpec
)t
).Element
;
829 /// This method is not implemented by MS runtime for dynamic types
831 public static bool HasElementType (TypeSpec t
)
833 return t
is ElementTypeSpec
;
836 static NumberFormatInfo nf_provider
= CultureInfo
.CurrentCulture
.NumberFormat
;
838 // This is a custom version of Convert.ChangeType() which works
839 // with the TypeBuilder defined types when compiling corlib.
840 public static object ChangeType (object value, TypeSpec targetType
, out bool error
)
842 IConvertible convert_value
= value as IConvertible
;
844 if (convert_value
== null){
850 // We cannot rely on build-in type conversions as they are
851 // more limited than what C# supports.
852 // See char -> float/decimal/double conversion
856 if (targetType
== TypeManager
.bool_type
)
857 return convert_value
.ToBoolean (nf_provider
);
858 if (targetType
== TypeManager
.byte_type
)
859 return convert_value
.ToByte (nf_provider
);
860 if (targetType
== TypeManager
.char_type
)
861 return convert_value
.ToChar (nf_provider
);
862 if (targetType
== TypeManager
.short_type
)
863 return convert_value
.ToInt16 (nf_provider
);
864 if (targetType
== TypeManager
.int32_type
)
865 return convert_value
.ToInt32 (nf_provider
);
866 if (targetType
== TypeManager
.int64_type
)
867 return convert_value
.ToInt64 (nf_provider
);
868 if (targetType
== TypeManager
.sbyte_type
)
869 return convert_value
.ToSByte (nf_provider
);
871 if (targetType
== TypeManager
.decimal_type
) {
872 if (convert_value
.GetType () == typeof (char))
873 return (decimal) convert_value
.ToInt32 (nf_provider
);
874 return convert_value
.ToDecimal (nf_provider
);
877 if (targetType
== TypeManager
.double_type
) {
878 if (convert_value
.GetType () == typeof (char))
879 return (double) convert_value
.ToInt32 (nf_provider
);
880 return convert_value
.ToDouble (nf_provider
);
883 if (targetType
== TypeManager
.float_type
) {
884 if (convert_value
.GetType () == typeof (char))
885 return (float)convert_value
.ToInt32 (nf_provider
);
886 return convert_value
.ToSingle (nf_provider
);
889 if (targetType
== TypeManager
.string_type
)
890 return convert_value
.ToString (nf_provider
);
891 if (targetType
== TypeManager
.ushort_type
)
892 return convert_value
.ToUInt16 (nf_provider
);
893 if (targetType
== TypeManager
.uint32_type
)
894 return convert_value
.ToUInt32 (nf_provider
);
895 if (targetType
== TypeManager
.uint64_type
)
896 return convert_value
.ToUInt64 (nf_provider
);
897 if (targetType
== TypeManager
.object_type
)
908 /// Utility function that can be used to probe whether a type
909 /// is managed or not.
911 public static bool VerifyUnmanaged (CompilerContext ctx
, TypeSpec t
, Location loc
)
914 t
= GetElementType (t
);
916 if (IsUnmanagedType (t
))
919 ctx
.Report
.SymbolRelatedToPreviousError (t
);
920 ctx
.Report
.Error (208, loc
,
921 "Cannot take the address of, get the size of, or declare a pointer to a managed type `{0}'",
928 // Returns whether the array of memberinfos contains the given method
930 public static bool ArrayContainsMethod (List
<MemberSpec
> array
, MethodSpec new_method
, bool ignoreDeclType
)
932 AParametersCollection new_args
= new_method
.Parameters
;
934 foreach (MethodSpec method
in array
) {
935 if (!ignoreDeclType
&& method
.DeclaringType
!= new_method
.DeclaringType
)
938 if (method
.Name
!= new_method
.Name
)
941 if (!TypeSpecComparer
.Override
.IsEqual (method
.ReturnType
, new_method
.ReturnType
))
944 AParametersCollection old_args
= method
.Parameters
;
945 int old_count
= old_args
.Count
;
948 if (new_args
.Count
!= old_count
)
951 for (i
= 0; i
< old_count
; i
++) {
952 if (!TypeSpecComparer
.Override
.IsEqual (old_args
.Types
[i
], new_args
.Types
[i
]))
964 // This method always return false for non-generic compiler,
965 // while Type.IsGenericParameter is returned if it is supported.
966 public static bool IsGenericParameter (TypeSpec type
)
968 return type
.IsGenericParameter
;
971 public static bool IsGenericType (TypeSpec type
)
973 return type
.IsGeneric
;
976 // TODO: Implement correctly
977 public static bool ContainsGenericParameters (TypeSpec type
)
979 return type
.GetMetaInfo ().ContainsGenericParameters
;
982 public static bool IsEqual (TypeSpec a
, TypeSpec b
)
984 return a
== b
&& !(a
is InternalType
);
987 public static TypeSpec
[] GetTypeArguments (TypeSpec t
)
989 // TODO: return empty array !!
990 return t
.TypeArguments
;
994 /// Check whether `type' and `parent' are both instantiations of the same
995 /// generic type. Note that we do not check the type parameters here.
997 public static bool IsInstantiationOfSameGenericType (TypeSpec type
, TypeSpec parent
)
999 return type
== parent
|| type
.MemberDefinition
== parent
.MemberDefinition
;
1002 public static bool IsNullableType (TypeSpec t
)
1004 return generic_nullable_type
== t
.GetDefinition ();
1009 // Looks up a member called `name' in the `queried_type'. This lookup
1010 // is done by code that is contained in the definition for `invocation_type'
1011 // through a qualifier of type `qualifier_type' (or null if there is no qualifier).
1013 // `invocation_type' is used to check whether we're allowed to access the requested
1014 // member wrt its protection level.
1016 // When called from MemberAccess, `qualifier_type' is the type which is used to access
1017 // the requested member (`class B { A a = new A (); a.foo = 5; }'; here invocation_type
1018 // is B and qualifier_type is A). This is used to do the CS1540 check.
1020 // When resolving a SimpleName, `qualifier_type' is null.
1022 // The `qualifier_type' is used for the CS1540 check; it's normally either null or
1023 // the same than `queried_type' - except when we're being called from BaseAccess;
1024 // in this case, `invocation_type' is the current type and `queried_type' the base
1025 // type, so this'd normally trigger a CS1540.
1027 // The binding flags are `bf' and the kind of members being looked up are `mt'
1029 // The return value always includes private members which code in `invocation_type'
1030 // is allowed to access (using the specified `qualifier_type' if given); only use
1031 // BindingFlags.NonPublic to bypass the permission check.
1033 // The 'almost_match' argument is used for reporting error CS1540.
1035 // Returns an array of a single element for everything but Methods/Constructors
1036 // that might return multiple matches.
1038 public static IList
<MemberSpec
> MemberLookup (TypeSpec invocation_type
, TypeSpec qualifier_type
,
1039 TypeSpec queried_type
, MemberKind mt
,
1040 BindingRestriction opt
, string name
, int arity
, IList
<MemberSpec
> almost_match
)
1042 Timer
.StartTimer (TimerType
.MemberLookup
);
1044 var retval
= RealMemberLookup (invocation_type
, qualifier_type
,
1045 queried_type
, mt
, opt
, name
, arity
, almost_match
);
1047 Timer
.StopTimer (TimerType
.MemberLookup
);
1052 static IList
<MemberSpec
> RealMemberLookup (TypeSpec invocation_type
, TypeSpec qualifier_type
,
1053 TypeSpec queried_type
, MemberKind mt
,
1054 BindingRestriction bf
, string name
, int arity
, IList
<MemberSpec
> almost_match
)
1056 MemberFilter filter
= new MemberFilter (name
, arity
, mt
, null, null);
1057 if ((bf
& BindingRestriction
.AccessibleOnly
) != 0) {
1058 filter
.InvocationType
= invocation_type
?? InternalType
.FakeInternalType
;
1061 return MemberCache
.FindMembers (queried_type
, filter
, bf
);