2 // typespec.cs: Type specification
4 // Authors: Marek Safar (marek.safar@gmail.com)
6 // Dual licensed under the terms of the MIT X11 or GNU GPL
8 // Copyright 2010 Novell, Inc
12 using System
.Collections
.Generic
;
18 public class TypeSpec
: MemberSpec
21 protected MemberCache cache
;
22 protected IList
<TypeSpec
> ifaces
;
25 Dictionary
<TypeSpec
[], InflatedTypeSpec
> inflated_instances
;
27 public static readonly TypeSpec
[] EmptyTypes
= new TypeSpec
[0];
29 // Reflection Emit hacking
30 static Type TypeBuilder
;
31 static Type GenericTypeBuilder
;
35 var assembly
= typeof (object).Assembly
;
36 TypeBuilder
= assembly
.GetType ("System.Reflection.Emit.TypeBuilder");
37 GenericTypeBuilder
= assembly
.GetType ("System.Reflection.MonoGenericClass");
38 if (GenericTypeBuilder
== null)
39 GenericTypeBuilder
= assembly
.GetType ("System.Reflection.Emit.TypeBuilderInstantiation");
42 public TypeSpec (MemberKind kind
, TypeSpec declaringType
, ITypeDefinition definition
, Type info
, Modifiers modifiers
)
43 : base (kind
, declaringType
, definition
, modifiers
)
45 this.declaringType
= declaringType
;
48 if (definition
!= null && definition
.TypeParametersCount
> 0)
49 state
|= StateFlags
.IsGeneric
;
54 public override int Arity
{
56 return MemberDefinition
.TypeParametersCount
;
60 public virtual TypeSpec BaseType
{
69 public virtual IList
<TypeSpec
> Interfaces
{
79 get { return this is ArrayContainer; }
82 public bool IsAttribute
{
92 if (type
== TypeManager
.attribute_type
)
95 type
= type
.base_type
;
96 } while (type
!= null);
102 public bool IsInterface
{
104 return Kind
== MemberKind
.Interface
;
108 public bool IsClass
{
110 return Kind
== MemberKind
.Class
;
114 public bool IsConstantCompatible
{
116 if ((Kind
& (MemberKind
.Enum
| MemberKind
.Class
| MemberKind
.Interface
| MemberKind
.Delegate
)) != 0)
119 return TypeManager
.IsPrimitiveType (this) || this == TypeManager
.decimal_type
|| this == InternalType
.Dynamic
;
123 public bool IsDelegate
{
125 return Kind
== MemberKind
.Delegate
;
130 get { return Kind == MemberKind.Enum; }
133 // TODO: Should probably do
134 // IsGenericType -- recursive
135 // HasTypeParameter -- non-recursive
136 public bool IsGenericOrParentIsGeneric
{
142 ts
= ts
.declaringType
;
143 } while (ts
!= null);
149 public bool IsGenericParameter
{
150 get { return Kind == MemberKind.TypeParameter; }
153 public bool IsNested
{
154 get { return declaringType != null && Kind != MemberKind.TypeParameter; }
157 public bool IsPointer
{
159 return Kind
== MemberKind
.PointerType
;
163 public bool IsSealed
{
164 get { return (Modifiers & Modifiers.SEALED) != 0; }
167 public bool IsStruct
{
169 return Kind
== MemberKind
.Struct
;
173 public bool IsTypeBuilder
{
175 var meta
= GetMetaInfo().GetType ();
176 return meta
== TypeBuilder
|| meta
== GenericTypeBuilder
;
180 public MemberCache MemberCache
{
182 if (cache
== null || (state
& StateFlags
.PendingMemberCacheMembers
) != 0)
183 InitializeMemberCache (false);
189 throw new InternalErrorException ("Membercache reset");
195 public virtual MemberCache MemberCacheTypes
{
201 public new ITypeDefinition MemberDefinition
{
203 return (ITypeDefinition
) definition
;
207 // TODO: Wouldn't be better to rely on cast to InflatedTypeSpec and
208 // remove the property, YES IT WOULD !!!
209 public virtual TypeSpec
[] TypeArguments
{
210 get { return TypeSpec.EmptyTypes; }
215 public bool AddInterface (TypeSpec iface
)
217 if ((state
& StateFlags
.InterfacesExpanded
) != 0)
218 throw new InternalErrorException ("Modifying expanded interface list");
220 if (ifaces
== null) {
221 ifaces
= new List
<TypeSpec
> () { iface }
;
225 if (!ifaces
.Contains (iface
)) {
233 public AttributeUsageAttribute
GetAttributeUsage (PredefinedAttribute pa
)
235 if (Kind
!= MemberKind
.Class
)
236 throw new InternalErrorException ();
239 return Attribute
.DefaultUsageAttribute
;
241 AttributeUsageAttribute aua
= null;
243 while (type
!= null) {
244 aua
= type
.MemberDefinition
.GetAttributeUsage (pa
);
248 type
= type
.BaseType
;
254 public virtual Type
GetMetaInfo ()
259 public virtual TypeSpec
GetDefinition ()
264 public override string GetSignatureForError ()
269 s
= DeclaringType
.GetSignatureForError ();
271 s
= MemberDefinition
.Namespace
;
274 if (!string.IsNullOrEmpty (s
))
277 return s
+ Name
+ GetTypeNameSignature ();
280 protected virtual string GetTypeNameSignature ()
285 return "<" + TypeManager
.CSharpName (MemberDefinition
.TypeParameters
) + ">";
288 public bool ImplementsInterface (TypeSpec iface
)
292 if (t
.Interfaces
!= null) { // TODO: Try t.iface
293 foreach (TypeSpec i
in t
.Interfaces
) {
294 if (i
== iface
|| TypeSpecComparer
.Variant
.IsEqual (i
, iface
))
305 protected virtual void InitializeMemberCache (bool onlyTypes
)
308 // Not interested in members of nested private types
311 cache
= new MemberCache (0);
313 cache
= MemberDefinition
.LoadMembers (this);
317 public override MemberSpec
InflateMember (TypeParameterInflator inflator
)
319 var targs
= IsGeneric
? MemberDefinition
.TypeParameters
: TypeSpec
.EmptyTypes
;
322 // When inflating nested type from inside the type instance will be same
323 // because type parameters are same for all nested types
325 if (DeclaringType
== inflator
.TypeInstance
)
326 return MakeGenericType (targs
);
328 return new InflatedTypeSpec (this, inflator
.TypeInstance
, targs
);
331 public InflatedTypeSpec
MakeGenericType (TypeSpec
[] targs
)
333 if (targs
.Length
== 0 && !IsNested
)
334 throw new ArgumentException ("Empty type arguments");
336 InflatedTypeSpec instance
;
338 if (inflated_instances
== null)
339 inflated_instances
= new Dictionary
<TypeSpec
[], InflatedTypeSpec
> (TypeSpecComparer
.Default
);
341 if (!inflated_instances
.TryGetValue (targs
, out instance
)) {
342 if (GetDefinition () != this && !IsNested
)
343 throw new InternalErrorException ("Only type definition or nested non-inflated types can be used to call MakeGenericType");
345 instance
= new InflatedTypeSpec (this, declaringType
, targs
);
346 inflated_instances
.Add (targs
, instance
);
352 public virtual TypeSpec
Mutate (TypeParameterMutator mutator
)
357 public void SetMetaInfo (Type info
)
359 if (this.info
!= null)
360 throw new InternalErrorException ("MetaInfo reset");
365 public void SetExtensionMethodContainer ()
367 modifiers
|= Modifiers
.METHOD_EXTENSION
;
371 public class PredefinedTypeSpec
: TypeSpec
376 public PredefinedTypeSpec (MemberKind kind
, string ns
, string name
)
377 : base (kind
, null, null, null, Modifiers
.PUBLIC
)
383 public override int Arity
{
389 public override string Name
{
395 public string Namespace
{
401 public override string GetSignatureForError ()
404 case "Int32": return "int";
405 case "Int64": return "long";
406 case "String": return "string";
407 case "Boolean": return "bool";
408 case "Void": return "void";
409 case "Object": return "object";
410 case "UInt32": return "uint";
411 case "Int16": return "short";
412 case "UInt16": return "ushort";
413 case "UInt64": return "ulong";
414 case "Single": return "float";
415 case "Double": return "double";
416 case "Decimal": return "decimal";
417 case "Char": return "char";
418 case "Byte": return "byte";
419 case "SByte": return "sbyte";
422 return ns
+ "." + name
;
425 public void SetDefinition (ITypeDefinition td
, Type type
)
427 this.definition
= td
;
431 public void SetDefinition (TypeSpec ts
)
433 this.definition
= ts
.MemberDefinition
;
434 this.info
= ts
.GetMetaInfo ();
435 this.BaseType
= ts
.BaseType
;
436 this.Interfaces
= ts
.Interfaces
;
440 static class TypeSpecComparer
443 // Default reference comparison
445 public static readonly DefaultImpl Default
= new DefaultImpl ();
447 public class DefaultImpl
: IEqualityComparer
<TypeSpec
[]>, IEqualityComparer
<Tuple
<TypeSpec
, TypeSpec
[]>>
449 #region IEqualityComparer<TypeSpec[]> Members
451 public bool Equals (TypeSpec
[] x
, TypeSpec
[] y
)
453 if (x
.Length
!= y
.Length
)
459 for (int i
= 0; i
< x
.Length
; ++i
)
466 public int GetHashCode (TypeSpec
[] obj
)
469 for (int i
= 0; i
< obj
.Length
; ++i
)
470 hash
= (hash
<< 5) - hash
+ obj
[i
].GetHashCode ();
477 #region IEqualityComparer<Tuple<TypeSpec,TypeSpec[]>> Members
479 bool IEqualityComparer
<Tuple
<TypeSpec
, TypeSpec
[]>>.Equals (Tuple
<TypeSpec
, TypeSpec
[]> x
, Tuple
<TypeSpec
, TypeSpec
[]> y
)
481 return Equals (x
.Item2
, y
.Item2
) && x
.Item1
== y
.Item1
;
484 int IEqualityComparer
<Tuple
<TypeSpec
, TypeSpec
[]>>.GetHashCode (Tuple
<TypeSpec
, TypeSpec
[]> obj
)
486 return GetHashCode (obj
.Item2
) ^ obj
.Item1
.GetHashCode ();
493 // When comparing type signature of overrides or overloads
494 // this version tolerates different MVARs at same position
496 public static class Override
498 public static bool IsEqual (TypeSpec a
, TypeSpec b
)
504 // Consider the following example:
506 // public abstract class A
508 // public abstract T Foo<T>();
511 // public class B : A
513 // public override U Foo<T>() { return default (U); }
516 // Here, `T' and `U' are method type parameters from different methods
517 // (A.Foo and B.Foo), so both `==' and Equals() will fail.
519 // However, since we're determining whether B.Foo() overrides A.Foo(),
520 // we need to do a signature based comparision and consider them equal.
523 var tp_a
= a
as TypeParameterSpec
;
525 var tp_b
= b
as TypeParameterSpec
;
526 return tp_b
!= null && tp_a
.IsMethodOwned
== tp_b
.IsMethodOwned
&& tp_a
.DeclaredPosition
== tp_b
.DeclaredPosition
;
529 if (a
.TypeArguments
.Length
!= b
.TypeArguments
.Length
)
532 if (a
.TypeArguments
.Length
!= 0) {
533 if (a
.MemberDefinition
!= b
.MemberDefinition
)
536 for (int i
= 0; i
< a
.TypeArguments
.Length
; ++i
) {
537 if (!IsEqual (a
.TypeArguments
[i
], b
.TypeArguments
[i
]))
544 var ac_a
= a
as ArrayContainer
;
546 var ac_b
= b
as ArrayContainer
;
547 return ac_b
!= null && ac_a
.Rank
== ac_b
.Rank
&& IsEqual (ac_a
.Element
, ac_b
.Element
);
550 if (a
== InternalType
.Dynamic
|| b
== InternalType
.Dynamic
)
551 return b
== TypeManager
.object_type
|| a
== TypeManager
.object_type
;
557 // Compares unordered arrays
559 public static bool IsSame (TypeSpec
[] a
, TypeSpec
[] b
)
564 if (a
== null || b
== null || a
.Length
!= b
.Length
)
567 for (int ai
= 0; ai
< a
.Length
; ++ai
) {
569 for (int bi
= 0; bi
< b
.Length
; ++bi
) {
570 if (IsEqual (a
[ai
], b
[bi
])) {
583 public static bool IsEqual (AParametersCollection a
, AParametersCollection b
)
588 if (a
.Count
!= b
.Count
)
591 for (int i
= 0; i
< a
.Count
; ++i
) {
592 if (!IsEqual (a
.Types
[i
], b
.Types
[i
]))
595 const Parameter
.Modifier ref_out
= Parameter
.Modifier
.REF
| Parameter
.Modifier
.OUT
;
596 if ((a
.FixedParameters
[i
].ModFlags
& ref_out
) != (b
.FixedParameters
[i
].ModFlags
& ref_out
))
605 // Type variance equality comparison
607 public static class Variant
609 public static bool IsEqual (TypeSpec type1
, TypeSpec type2
)
611 if (!type1
.IsGeneric
|| !type2
.IsGeneric
)
614 var target_type_def
= type2
.MemberDefinition
;
615 if (type1
.MemberDefinition
!= target_type_def
)
618 if (!type1
.IsInterface
&& !type1
.IsDelegate
)
621 var t1_targs
= type1
.TypeArguments
;
622 var t2_targs
= type2
.TypeArguments
;
623 var targs_definition
= target_type_def
.TypeParameters
;
624 for (int i
= 0; i
< targs_definition
.Length
; ++i
) {
625 Variance v
= targs_definition
[i
].Variance
;
626 if (v
== Variance
.None
) {
627 if (t1_targs
[i
] == t2_targs
[i
])
632 if (v
== Variance
.Covariant
) {
633 if (!Convert
.ImplicitReferenceConversionExists (new EmptyExpression (t1_targs
[i
]), t2_targs
[i
]))
635 } else if (!Convert
.ImplicitReferenceConversionExists (new EmptyExpression (t2_targs
[i
]), t1_targs
[i
])) {
645 // Checks whether two generic instances may become equal for some
646 // particular instantiation (26.3.1).
648 public static class Unify
651 // Either @a or @b must be generic type
653 public static bool IsEqual (TypeSpec a
, TypeSpec b
)
655 if (a
.MemberDefinition
!= b
.MemberDefinition
)
658 var ta
= a
.TypeArguments
;
659 var tb
= b
.TypeArguments
;
660 for (int i
= 0; i
< ta
.Length
; i
++) {
661 if (!MayBecomeEqualGenericTypes (ta
[i
], tb
[i
]))
668 static bool ContainsTypeParameter (TypeSpec tparam
, TypeSpec type
)
670 TypeSpec
[] targs
= type
.TypeArguments
;
671 for (int i
= 0; i
< targs
.Length
; i
++) {
672 if (tparam
== targs
[i
])
675 if (ContainsTypeParameter (tparam
, targs
[i
]))
683 /// Check whether `a' and `b' may become equal generic types.
684 /// The algorithm to do that is a little bit complicated.
686 static bool MayBecomeEqualGenericTypes (TypeSpec a
, TypeSpec b
)
688 if (a
.IsGenericParameter
) {
690 // If a is an array of a's type, they may never
697 // If b is a generic parameter or an actual type,
698 // they may become equal:
700 // class X<T,U> : I<T>, I<U>
701 // class X<T> : I<T>, I<float>
703 if (b
.IsGenericParameter
)
704 return a
.DeclaringType
== b
.DeclaringType
;
707 // We're now comparing a type parameter with a
708 // generic instance. They may become equal unless
709 // the type parameter appears anywhere in the
712 // class X<T,U> : I<T>, I<X<U>>
713 // -> error because you could instanciate it as
716 // class X<T> : I<T>, I<X<T>> -> ok
719 return !ContainsTypeParameter (a
, b
);
722 if (b
.IsGenericParameter
)
723 return MayBecomeEqualGenericTypes (b
, a
);
726 // At this point, neither a nor b are a type parameter.
728 // If one of them is a generic instance, compare them (if the
729 // other one is not a generic instance, they can never
732 if (TypeManager
.IsGenericType (a
) || TypeManager
.IsGenericType (b
))
733 return IsEqual (a
, b
);
736 // If both of them are arrays.
738 var a_ac
= a
as ArrayContainer
;
740 var b_ac
= b
as ArrayContainer
;
741 if (b_ac
== null || a_ac
.Rank
!= b_ac
.Rank
)
744 return MayBecomeEqualGenericTypes (a_ac
.Element
, b_ac
.Element
);
748 // Ok, two ordinary types.
755 public interface ITypeDefinition
: IMemberDefinition
757 string Namespace { get; }
758 int TypeParametersCount { get; }
759 TypeParameterSpec
[] TypeParameters { get; }
761 TypeSpec
GetAttributeCoClass ();
762 string GetAttributeDefaultMember ();
763 AttributeUsageAttribute
GetAttributeUsage (PredefinedAttribute pa
);
764 MemberCache
LoadMembers (TypeSpec declaringType
);
767 class InternalType
: TypeSpec
769 private class DynamicType
: InternalType
771 public DynamicType ()
776 public override Type
GetMetaInfo ()
778 return typeof (object);
782 public static readonly TypeSpec AnonymousMethod
= new InternalType ("anonymous method");
783 public static readonly TypeSpec Arglist
= new InternalType ("__arglist");
784 public static readonly TypeSpec Dynamic
= new DynamicType ();
785 public static readonly TypeSpec MethodGroup
= new InternalType ("method group");
786 public static readonly TypeSpec Null
= new InternalType ("null");
787 public static readonly TypeSpec FakeInternalType
= new InternalType ("<fake$type>");
789 readonly string name
;
791 protected InternalType (string name
)
792 : base (MemberKind
.InternalCompilerType
, null, null, null, Modifiers
.PUBLIC
)
795 cache
= MemberCache
.Empty
;
797 // Make all internal types CLS-compliant, non-obsolete
798 state
= (state
& ~
(StateFlags
.CLSCompliant_Undetected
| StateFlags
.Obsolete_Undetected
)) | StateFlags
.CLSCompliant
;
801 public override string Name
{
807 public override string GetSignatureForError ()
813 public abstract class ElementTypeSpec
: TypeSpec
815 protected ElementTypeSpec (MemberKind kind
, TypeSpec element
, Type info
)
816 : base (kind
, element
.DeclaringType
, element
.MemberDefinition
, info
, element
.Modifiers
)
818 this.Element
= element
;
819 cache
= MemberCache
.Empty
;
824 public TypeSpec Element { get; private set; }
826 public override string Name
{
828 throw new NotSupportedException ();
834 public override ObsoleteAttribute
GetAttributeObsolete ()
836 return Element
.GetAttributeObsolete ();
839 protected virtual string GetPostfixSignature ()
844 public override string GetSignatureForError ()
846 return Element
.GetSignatureForError () + GetPostfixSignature ();
849 public override TypeSpec
Mutate (TypeParameterMutator mutator
)
851 var me
= Element
.Mutate (mutator
);
855 var mutated
= (ElementTypeSpec
) MemberwiseClone ();
856 mutated
.Element
= me
;
862 public class ArrayContainer
: ElementTypeSpec
865 static Dictionary
<Tuple
<TypeSpec
, int>, ArrayContainer
> instances
= new Dictionary
<Tuple
<TypeSpec
, int>, ArrayContainer
> ();
867 private ArrayContainer (TypeSpec element
, int rank
)
868 : base (MemberKind
.Class
, element
, null)
879 public System
.Reflection
.MethodInfo
GetConstructor ()
881 var mb
= RootContext
.ToplevelTypes
.Builder
;
883 var arg_types
= new Type
[rank
];
884 for (int i
= 0; i
< rank
; i
++)
885 arg_types
[i
] = TypeManager
.int32_type
.GetMetaInfo ();
887 var ctor
= mb
.GetArrayMethod (
888 GetMetaInfo (), ".ctor",
889 System
.Reflection
.CallingConventions
.HasThis
,
895 public System
.Reflection
.MethodInfo
GetAddressMethod ()
897 var mb
= RootContext
.ToplevelTypes
.Builder
;
899 var arg_types
= new Type
[rank
];
900 for (int i
= 0; i
< rank
; i
++)
901 arg_types
[i
] = TypeManager
.int32_type
.GetMetaInfo ();
903 var address
= mb
.GetArrayMethod (
904 GetMetaInfo (), "Address",
905 System
.Reflection
.CallingConventions
.HasThis
| System
.Reflection
.CallingConventions
.Standard
,
906 ReferenceContainer
.MakeType (Element
).GetMetaInfo (), arg_types
);
911 public System
.Reflection
.MethodInfo
GetGetMethod ()
913 var mb
= RootContext
.ToplevelTypes
.Builder
;
915 var arg_types
= new Type
[rank
];
916 for (int i
= 0; i
< rank
; i
++)
917 arg_types
[i
] = TypeManager
.int32_type
.GetMetaInfo ();
919 var get = mb
.GetArrayMethod (
920 GetMetaInfo (), "Get",
921 System
.Reflection
.CallingConventions
.HasThis
| System
.Reflection
.CallingConventions
.Standard
,
922 Element
.GetMetaInfo (), arg_types
);
927 public System
.Reflection
.MethodInfo
GetSetMethod ()
929 var mb
= RootContext
.ToplevelTypes
.Builder
;
931 var arg_types
= new Type
[rank
+ 1];
932 for (int i
= 0; i
< rank
; i
++)
933 arg_types
[i
] = TypeManager
.int32_type
.GetMetaInfo ();
935 arg_types
[rank
] = Element
.GetMetaInfo ();
937 var set = mb
.GetArrayMethod (
938 GetMetaInfo (), "Set",
939 System
.Reflection
.CallingConventions
.HasThis
| System
.Reflection
.CallingConventions
.Standard
,
940 TypeManager
.void_type
.GetMetaInfo (), arg_types
);
945 public override Type
GetMetaInfo ()
949 info
= Element
.GetMetaInfo ().MakeArrayType ();
951 info
= Element
.GetMetaInfo ().MakeArrayType (rank
);
957 protected override string GetPostfixSignature()
959 StringBuilder sb
= new StringBuilder ();
961 for (int i
= 1; i
< rank
; i
++) {
966 return sb
.ToString ();
969 public static ArrayContainer
MakeType (TypeSpec element
)
971 return MakeType (element
, 1);
974 public static ArrayContainer
MakeType (TypeSpec element
, int rank
)
977 var key
= Tuple
.Create (element
, rank
);
978 if (!instances
.TryGetValue (key
, out ac
)) {
979 ac
= new ArrayContainer (element
, rank
) {
980 BaseType
= TypeManager
.array_type
983 instances
.Add (key
, ac
);
989 public static void Reset ()
991 instances
= new Dictionary
<Tuple
<TypeSpec
, int>, ArrayContainer
> ();
995 class ReferenceContainer
: ElementTypeSpec
997 static Dictionary
<TypeSpec
, ReferenceContainer
> instances
= new Dictionary
<TypeSpec
, ReferenceContainer
> ();
999 private ReferenceContainer (TypeSpec element
)
1000 : base (MemberKind
.Class
, element
, null) // TODO: Kind.Class is most likely wrong
1004 public override Type
GetMetaInfo ()
1007 info
= Element
.GetMetaInfo ().MakeByRefType ();
1013 public static ReferenceContainer
MakeType (TypeSpec element
)
1015 ReferenceContainer pc
;
1016 if (!instances
.TryGetValue (element
, out pc
)) {
1017 pc
= new ReferenceContainer (element
);
1018 instances
.Add (element
, pc
);
1024 public static void Reset ()
1026 instances
= new Dictionary
<TypeSpec
, ReferenceContainer
> ();
1030 class PointerContainer
: ElementTypeSpec
1032 static Dictionary
<TypeSpec
, PointerContainer
> instances
= new Dictionary
<TypeSpec
, PointerContainer
> ();
1034 private PointerContainer (TypeSpec element
)
1035 : base (MemberKind
.PointerType
, element
, null)
1037 // It's never CLS-Compliant
1038 state
&= ~StateFlags
.CLSCompliant_Undetected
;
1041 public override Type
GetMetaInfo ()
1044 info
= Element
.GetMetaInfo ().MakePointerType ();
1050 protected override string GetPostfixSignature()
1055 public static PointerContainer
MakeType (TypeSpec element
)
1057 PointerContainer pc
;
1058 if (!instances
.TryGetValue (element
, out pc
)) {
1059 pc
= new PointerContainer (element
);
1060 instances
.Add (element
, pc
);
1066 public static void Reset ()
1068 instances
= new Dictionary
<TypeSpec
, PointerContainer
> ();