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
9 // Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
13 using System.Collections.Generic;
18 using MetaType = IKVM.Reflection.Type;
19 using IKVM.Reflection;
21 using MetaType = System.Type;
22 using System.Reflection;
28 // Inflated or non-inflated representation of any type.
30 public class TypeSpec : MemberSpec
32 protected MetaType info;
33 protected MemberCache cache;
34 protected IList<TypeSpec> ifaces;
37 Dictionary<TypeSpec[], InflatedTypeSpec> inflated_instances;
39 public static readonly TypeSpec[] EmptyTypes = new TypeSpec[0];
42 // Reflection Emit hacking
43 static readonly Type TypeBuilder;
44 static readonly Type GenericTypeBuilder;
48 var assembly = typeof (object).Assembly;
49 TypeBuilder = assembly.GetType ("System.Reflection.Emit.TypeBuilder");
50 GenericTypeBuilder = assembly.GetType ("System.Reflection.MonoGenericClass");
51 if (GenericTypeBuilder == null)
52 GenericTypeBuilder = assembly.GetType ("System.Reflection.Emit.TypeBuilderInstantiation");
56 public TypeSpec (MemberKind kind, TypeSpec declaringType, ITypeDefinition definition, MetaType info, Modifiers modifiers)
57 : base (kind, declaringType, definition, modifiers)
59 this.declaringType = declaringType;
62 if (definition != null && definition.TypeParametersCount > 0)
63 state |= StateFlags.IsGeneric;
68 public override int Arity {
70 return MemberDefinition.TypeParametersCount;
74 public virtual TypeSpec BaseType {
83 public virtual BuiltinTypeSpec.Type BuiltinType {
85 return BuiltinTypeSpec.Type.None;
89 public bool HasDynamicElement {
91 return (state & StateFlags.HasDynamicElement) != 0;
96 // Returns a list of all interfaces including
97 // interfaces from base type or base interfaces
99 public virtual IList<TypeSpec> Interfaces {
108 public bool IsArray {
110 return Kind == MemberKind.ArrayType;
114 public bool IsAttribute {
121 if (type.BuiltinType == BuiltinTypeSpec.Type.Attribute)
127 type = type.base_type;
128 } while (type != null);
134 public bool IsInterface {
136 return Kind == MemberKind.Interface;
140 public bool IsClass {
142 return Kind == MemberKind.Class;
146 public bool IsConstantCompatible {
148 if ((Kind & (MemberKind.Enum | MemberKind.Class | MemberKind.Interface | MemberKind.Delegate | MemberKind.ArrayType)) != 0)
151 switch (BuiltinType) {
152 case BuiltinTypeSpec.Type.Int:
153 case BuiltinTypeSpec.Type.UInt:
154 case BuiltinTypeSpec.Type.Long:
155 case BuiltinTypeSpec.Type.ULong:
156 case BuiltinTypeSpec.Type.Float:
157 case BuiltinTypeSpec.Type.Double:
158 case BuiltinTypeSpec.Type.Char:
159 case BuiltinTypeSpec.Type.Short:
160 case BuiltinTypeSpec.Type.Decimal:
161 case BuiltinTypeSpec.Type.Bool:
162 case BuiltinTypeSpec.Type.SByte:
163 case BuiltinTypeSpec.Type.Byte:
164 case BuiltinTypeSpec.Type.UShort:
165 case BuiltinTypeSpec.Type.Dynamic:
173 public bool IsDelegate {
175 return Kind == MemberKind.Delegate;
180 // Returns true for instances of Expression<T>
182 public virtual bool IsExpressionTreeType {
187 state = value ? state | StateFlags.InflatedExpressionType : state & ~StateFlags.InflatedExpressionType;
193 return Kind == MemberKind.Enum;
198 // Returns true for instances of IList<T>, IEnumerable<T>, ICollection<T>
200 public virtual bool IsGenericIterateInterface {
205 state = value ? state | StateFlags.GenericIterateInterface : state & ~StateFlags.GenericIterateInterface;
210 // Returns true for instances of System.Threading.Tasks.Task<T>
212 public virtual bool IsGenericTask {
217 state = value ? state | StateFlags.GenericTask : state & ~StateFlags.GenericTask;
221 // TODO: Should probably do
222 // IsGenericType -- recursive
223 // HasTypeParameter -- non-recursive
224 public bool IsGenericOrParentIsGeneric {
230 ts = ts.declaringType;
231 } while (ts != null);
237 public bool IsGenericParameter {
239 return Kind == MemberKind.TypeParameter;
244 // Returns true for instances of Nullable<T>
246 public virtual bool IsNullableType {
251 state = value ? state | StateFlags.InflatedNullableType : state & ~StateFlags.InflatedNullableType;
255 public bool IsNested {
256 get { return declaringType != null && Kind != MemberKind.TypeParameter; }
259 public bool IsPointer {
261 return Kind == MemberKind.PointerType;
265 public bool IsSealed {
266 get { return (Modifiers & Modifiers.SEALED) != 0; }
269 public bool IsSpecialRuntimeType {
271 return (state & StateFlags.SpecialRuntimeType) != 0;
274 state = value ? state | StateFlags.SpecialRuntimeType : state & ~StateFlags.SpecialRuntimeType;
278 public bool IsStruct {
280 return Kind == MemberKind.Struct;
284 public bool IsTypeBuilder {
289 var meta = GetMetaInfo().GetType ();
290 return meta == TypeBuilder || meta == GenericTypeBuilder;
296 // Whether a type is unmanaged. This is used by the unsafe code
298 public bool IsUnmanaged {
301 return ((ElementTypeSpec) this).Element.IsUnmanaged;
303 var ds = MemberDefinition as TypeDefinition;
305 return ds.IsUnmanagedType ();
307 if (Kind == MemberKind.Void)
310 if (IsNested && DeclaringType.IsGenericOrParentIsGeneric)
313 return IsValueType (this);
318 // A cache of all type members (including nested types)
320 public MemberCache MemberCache {
322 if (cache == null || (state & StateFlags.PendingMemberCacheMembers) != 0)
323 InitializeMemberCache (false);
329 throw new InternalErrorException ("Membercache reset");
335 public MemberCache MemberCacheTypes {
338 InitializeMemberCache (true);
344 public new ITypeDefinition MemberDefinition {
346 return (ITypeDefinition) definition;
350 // TODO: Wouldn't be better to rely on cast to InflatedTypeSpec and
351 // remove the property, YES IT WOULD !!!
352 public virtual TypeSpec[] TypeArguments {
353 get { return TypeSpec.EmptyTypes; }
358 public virtual bool AddInterface (TypeSpec iface)
360 if ((state & StateFlags.InterfacesExpanded) != 0)
361 throw new InternalErrorException ("Modifying expanded interface list");
363 if (ifaces == null) {
364 ifaces = new List<TypeSpec> () { iface };
368 if (!ifaces.Contains (iface)) {
377 // Special version used during type definition
379 public bool AddInterfaceDefined (TypeSpec iface)
381 if (!AddInterface (iface))
385 // We can get into a situation where a type is inflated before
386 // its interfaces are resoved. Consider this situation
388 // class A<T> : X<A<int>>, IFoo {}
390 // When resolving base class of X`1 we inflate context type A`1
391 // All this happens before we even hit IFoo resolve. Without
392 // additional expansion any inside usage of A<T> would miss IFoo
393 // interface because it comes from early inflated A`1 definition.
395 if (inflated_instances != null) {
397 // Inflate only existing instances not any new instances added
398 // during AddInterface
400 var inflated_existing = inflated_instances.Values.ToArray ();
401 foreach (var inflated in inflated_existing) {
402 inflated.AddInterface (iface);
410 // Returns all type arguments, usefull for nested types
412 public static TypeSpec[] GetAllTypeArguments (TypeSpec type)
414 IList<TypeSpec> targs = TypeSpec.EmptyTypes;
417 if (type.Arity > 0) {
418 if (targs.Count == 0) {
419 targs = type.TypeArguments;
421 var list = targs as List<TypeSpec> ?? new List<TypeSpec> (targs);
422 list.AddRange (type.TypeArguments);
427 type = type.declaringType;
428 } while (type != null);
430 return targs as TypeSpec[] ?? ((List<TypeSpec>) targs).ToArray ();
433 public AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa)
435 if (Kind != MemberKind.Class)
436 throw new InternalErrorException ();
439 return Attribute.DefaultUsageAttribute;
441 AttributeUsageAttribute aua = null;
443 while (type != null) {
444 aua = type.MemberDefinition.GetAttributeUsage (pa);
448 type = type.BaseType;
455 // Return metadata information used during emit to describe the type
457 public virtual MetaType GetMetaInfo ()
462 public virtual TypeSpec GetDefinition ()
468 // Text representation of type used by documentation writer
470 public override string GetSignatureForDocumentation ()
472 StringBuilder sb = new StringBuilder ();
474 sb.Append (DeclaringType.GetSignatureForDocumentation ());
476 sb.Append (MemberDefinition.Namespace);
484 if (this is InflatedTypeSpec) {
486 for (int i = 0; i < Arity; ++i) {
490 sb.Append (TypeArguments[i].GetSignatureForDocumentation ());
495 sb.Append (Arity.ToString ());
499 return sb.ToString ();
502 public string GetExplicitNameSignatureForDocumentation ()
504 StringBuilder sb = new StringBuilder ();
506 sb.Append (DeclaringType.GetExplicitNameSignatureForDocumentation ());
507 } else if (MemberDefinition.Namespace != null) {
508 sb.Append (MemberDefinition.Namespace.Replace ('.', '#'));
517 for (int i = 0; i < Arity; ++i) {
521 sb.Append (TypeArguments[i].GetExplicitNameSignatureForDocumentation ());
526 return sb.ToString ();
529 public override string GetSignatureForError ()
534 s = DeclaringType.GetSignatureForError ();
535 } else if (MemberDefinition is AnonymousTypeClass) {
536 return ((AnonymousTypeClass) MemberDefinition).GetSignatureForError ();
538 s = MemberDefinition.Namespace;
541 if (!string.IsNullOrEmpty (s))
544 return s + Name + GetTypeNameSignature ();
547 public string GetSignatureForErrorIncludingAssemblyName ()
549 return string.Format ("{0} [{1}]", GetSignatureForError (), MemberDefinition.DeclaringAssembly.FullName);
552 protected virtual string GetTypeNameSignature ()
557 return "<" + TypeManager.CSharpName (MemberDefinition.TypeParameters) + ">";
560 public bool ImplementsInterface (TypeSpec iface, bool variantly)
562 var ifaces = Interfaces;
563 if (ifaces != null) {
564 for (int i = 0; i < ifaces.Count; ++i) {
565 if (TypeSpecComparer.IsEqual (ifaces[i], iface))
568 if (variantly && TypeSpecComparer.Variant.IsEqual (ifaces[i], iface))
576 protected virtual void InitializeMemberCache (bool onlyTypes)
579 MemberDefinition.LoadMembers (this, onlyTypes, ref cache);
580 } catch (Exception e) {
581 throw new InternalErrorException (e, "Unexpected error when loading type `{0}'", GetSignatureForError ());
585 state |= StateFlags.PendingMemberCacheMembers;
587 state &= ~StateFlags.PendingMemberCacheMembers;
591 // Is @baseClass base implementation of @type. With enabled @dynamicIsEqual the slower
592 // comparison is used to hide differences between `object' and `dynamic' for generic
593 // types. Should not be used for comparisons where G<object> != G<dynamic>
595 public static bool IsBaseClass (TypeSpec type, TypeSpec baseClass, bool dynamicIsObject)
597 if (dynamicIsObject && baseClass.IsGeneric) {
599 // Returns true for a hierarchies like this when passing baseClass of A<dynamic>
601 // class B : A<object> {}
603 type = type.BaseType;
604 while (type != null) {
605 if (TypeSpecComparer.IsEqual (type, baseClass))
608 type = type.BaseType;
614 while (type != null) {
615 type = type.BaseType;
616 if (type == baseClass)
623 public static bool IsReferenceType (TypeSpec t)
626 case MemberKind.TypeParameter:
627 return ((TypeParameterSpec) t).IsReferenceType;
628 case MemberKind.Struct:
629 case MemberKind.Enum:
630 case MemberKind.Void:
632 case MemberKind.InternalCompilerType:
634 // Null is considered to be a reference type
636 return t == InternalType.NullLiteral || t.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
642 public static bool IsValueType (TypeSpec t)
645 case MemberKind.TypeParameter:
646 return ((TypeParameterSpec) t).IsValueType;
647 case MemberKind.Struct:
648 case MemberKind.Enum:
655 public override MemberSpec InflateMember (TypeParameterInflator inflator)
657 var targs = IsGeneric ? MemberDefinition.TypeParameters : TypeSpec.EmptyTypes;
660 // When inflating nested type from inside the type instance will be same
661 // because type parameters are same for all nested types
663 if (DeclaringType == inflator.TypeInstance) {
664 return MakeGenericType (inflator.Context, targs);
667 return new InflatedTypeSpec (inflator.Context, this, inflator.TypeInstance, targs);
671 // Inflates current type using specific type arguments
673 public InflatedTypeSpec MakeGenericType (IModuleContext context, TypeSpec[] targs)
675 if (targs.Length == 0 && !IsNested)
676 throw new ArgumentException ("Empty type arguments for type " + GetSignatureForError ());
678 InflatedTypeSpec instance;
680 if (inflated_instances == null) {
681 inflated_instances = new Dictionary<TypeSpec[], InflatedTypeSpec> (TypeSpecComparer.Default);
684 instance = this as InflatedTypeSpec;
685 if (instance != null) {
687 // Nested types could be inflated on already inflated instances
688 // Caching this type ensured we are using same instance for
689 // inside/outside inflation using local type parameters
691 inflated_instances.Add (TypeArguments, instance);
696 if (!inflated_instances.TryGetValue (targs, out instance)) {
697 if (GetDefinition () != this && !IsNested)
698 throw new InternalErrorException ("`{0}' must be type definition or nested non-inflated type to MakeGenericType",
699 GetSignatureForError ());
701 instance = new InflatedTypeSpec (context, this, declaringType, targs);
702 inflated_instances.Add (targs, instance);
708 public virtual TypeSpec Mutate (TypeParameterMutator mutator)
713 public override List<TypeSpec> ResolveMissingDependencies ()
715 List<TypeSpec> missing = null;
717 if (Kind == MemberKind.MissingType) {
718 missing = new List<TypeSpec> ();
723 foreach (var targ in TypeArguments) {
724 if (targ.Kind == MemberKind.MissingType) {
726 missing = new List<TypeSpec> ();
732 if (Interfaces != null) {
733 foreach (var iface in Interfaces) {
734 if (iface.Kind == MemberKind.MissingType) {
736 missing = new List<TypeSpec> ();
743 if (MemberDefinition.TypeParametersCount > 0) {
744 foreach (var tp in MemberDefinition.TypeParameters) {
745 var tp_missing = tp.GetMissingDependencies ();
746 if (tp_missing != null) {
748 missing = new List<TypeSpec> ();
750 missing.AddRange (tp_missing);
755 if (missing != null || BaseType == null)
758 return BaseType.ResolveMissingDependencies ();
761 public void SetMetaInfo (MetaType info)
763 if (this.info != null)
764 throw new InternalErrorException ("MetaInfo reset");
769 public void SetExtensionMethodContainer ()
771 modifiers |= Modifiers.METHOD_EXTENSION;
776 // Special version used for types which must exist in corlib or
777 // the compiler cannot work
779 public sealed class BuiltinTypeSpec : TypeSpec
785 // Ordered carefully for fast compares
813 MulticastDelegate = 23,
826 readonly string name;
828 public BuiltinTypeSpec (MemberKind kind, string ns, string name, Type builtinKind)
829 : base (kind, null, null, null, Modifiers.PUBLIC)
831 this.type = builtinKind;
836 public BuiltinTypeSpec (string name, Type builtinKind)
837 : this (MemberKind.InternalCompilerType, "", name, builtinKind)
839 // Make all internal types CLS-compliant, non-obsolete, compact
840 state = (state & ~(StateFlags.CLSCompliant_Undetected | StateFlags.Obsolete_Undetected | StateFlags.MissingDependency_Undetected)) | StateFlags.CLSCompliant;
845 public override int Arity {
851 public override BuiltinTypeSpec.Type BuiltinType {
857 public string FullName {
859 return ns + '.' + name;
863 public override string Name {
869 public string Namespace {
877 public static bool IsPrimitiveType (TypeSpec type)
879 return type.BuiltinType >= Type.FirstPrimitive && type.BuiltinType <= Type.LastPrimitive;
882 public static bool IsPrimitiveTypeOrDecimal (TypeSpec type)
884 return type.BuiltinType >= Type.FirstPrimitive && type.BuiltinType <= Type.Decimal;
887 public override string GetSignatureForError ()
890 case "Int32": return "int";
891 case "Int64": return "long";
892 case "String": return "string";
893 case "Boolean": return "bool";
894 case "Void": return "void";
895 case "Object": return "object";
896 case "UInt32": return "uint";
897 case "Int16": return "short";
898 case "UInt16": return "ushort";
899 case "UInt64": return "ulong";
900 case "Single": return "float";
901 case "Double": return "double";
902 case "Decimal": return "decimal";
903 case "Char": return "char";
904 case "Byte": return "byte";
905 case "SByte": return "sbyte";
915 // Returns the size of type if known, otherwise, 0
917 public static int GetSize (TypeSpec type)
919 switch (type.BuiltinType) {
943 public void SetDefinition (ITypeDefinition td, MetaType type, Modifiers mod)
945 this.definition = td;
947 this.modifiers |= (mod & ~Modifiers.AccessibilityMask);
950 public void SetDefinition (TypeSpec ts)
952 this.definition = ts.MemberDefinition;
953 this.info = ts.GetMetaInfo ();
954 this.BaseType = ts.BaseType;
955 this.Interfaces = ts.Interfaces;
956 this.modifiers = ts.Modifiers;
961 // Various type comparers used by compiler
963 static class TypeSpecComparer
966 // Does strict reference comparion only
968 public static readonly DefaultImpl Default = new DefaultImpl ();
970 public class DefaultImpl : IEqualityComparer<TypeSpec[]>
972 #region IEqualityComparer<TypeSpec[]> Members
974 bool IEqualityComparer<TypeSpec[]>.Equals (TypeSpec[] x, TypeSpec[] y)
979 if (x.Length != y.Length)
982 for (int i = 0; i < x.Length; ++i)
989 int IEqualityComparer<TypeSpec[]>.GetHashCode (TypeSpec[] obj)
992 for (int i = 0; i < obj.Length; ++i)
993 hash = (hash << 5) - hash + obj[i].GetHashCode ();
1002 // When comparing type signature of overrides or overloads
1003 // this version tolerates different MVARs at same position
1005 public static class Override
1007 public static bool IsEqual (TypeSpec a, TypeSpec b)
1013 // Consider the following example:
1015 // public abstract class A
1017 // public abstract T Foo<T>();
1020 // public class B : A
1022 // public override U Foo<T>() { return default (U); }
1025 // Here, `T' and `U' are method type parameters from different methods
1026 // (A.Foo and B.Foo), so both `==' and Equals() will fail.
1028 // However, since we're determining whether B.Foo() overrides A.Foo(),
1029 // we need to do a signature based comparision and consider them equal.
1032 var tp_a = a as TypeParameterSpec;
1034 var tp_b = b as TypeParameterSpec;
1035 return tp_b != null && tp_a.IsMethodOwned == tp_b.IsMethodOwned && tp_a.DeclaredPosition == tp_b.DeclaredPosition;
1038 var ac_a = a as ArrayContainer;
1040 var ac_b = b as ArrayContainer;
1041 return ac_b != null && ac_a.Rank == ac_b.Rank && IsEqual (ac_a.Element, ac_b.Element);
1044 if (a.BuiltinType == BuiltinTypeSpec.Type.Dynamic || b.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1045 return b.BuiltinType == BuiltinTypeSpec.Type.Object || a.BuiltinType == BuiltinTypeSpec.Type.Object;
1047 if (a.MemberDefinition != b.MemberDefinition)
1051 for (int i = 0; i < a.TypeArguments.Length; ++i) {
1052 if (!IsEqual (a.TypeArguments[i], b.TypeArguments[i]))
1056 a = a.DeclaringType;
1057 b = b.DeclaringType;
1058 } while (a != null);
1063 public static bool IsEqual (TypeSpec[] a, TypeSpec[] b)
1068 if (a.Length != b.Length)
1071 for (int i = 0; i < a.Length; ++i) {
1072 if (!IsEqual (a[i], b[i]))
1081 // Compares unordered arrays
1083 public static bool IsSame (TypeSpec[] a, TypeSpec[] b)
1088 if (a == null || b == null || a.Length != b.Length)
1091 for (int ai = 0; ai < a.Length; ++ai) {
1093 for (int bi = 0; bi < b.Length; ++bi) {
1094 if (IsEqual (a[ai], b[bi])) {
1107 public static bool IsEqual (AParametersCollection a, AParametersCollection b)
1112 if (a.Count != b.Count)
1115 for (int i = 0; i < a.Count; ++i) {
1116 if (!IsEqual (a.Types[i], b.Types[i]))
1119 if ((a.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (b.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
1128 // Type variance equality comparison
1130 public static class Variant
1132 public static bool IsEqual (TypeSpec type1, TypeSpec type2)
1134 if (!type1.IsGeneric || !type2.IsGeneric)
1137 var target_type_def = type2.MemberDefinition;
1138 if (type1.MemberDefinition != target_type_def)
1141 var t1_targs = type1.TypeArguments;
1142 var t2_targs = type2.TypeArguments;
1143 var targs_definition = target_type_def.TypeParameters;
1145 if (!type1.IsInterface && !type1.IsDelegate) {
1149 for (int i = 0; i < targs_definition.Length; ++i) {
1150 if (TypeSpecComparer.IsEqual (t1_targs[i], t2_targs[i]))
1153 Variance v = targs_definition[i].Variance;
1154 if (v == Variance.None) {
1158 if (v == Variance.Covariant) {
1159 if (!Convert.ImplicitReferenceConversionExists (t1_targs[i], t2_targs[i]))
1161 } else if (!Convert.ImplicitReferenceConversionExists (t2_targs[i], t1_targs[i])) {
1171 // Checks whether two generic instances may become equal for some
1172 // particular instantiation (26.3.1).
1174 public static class Unify
1177 // Either @a or @b must be generic type
1179 public static bool IsEqual (TypeSpec a, TypeSpec b)
1181 if (a.MemberDefinition != b.MemberDefinition) {
1182 var base_ifaces = a.Interfaces;
1183 if (base_ifaces != null) {
1184 foreach (var base_iface in base_ifaces) {
1185 if (base_iface.Arity > 0 && IsEqual (base_iface, b))
1193 var ta = a.TypeArguments;
1194 var tb = b.TypeArguments;
1195 for (int i = 0; i < ta.Length; i++) {
1196 if (!MayBecomeEqualGenericTypes (ta[i], tb[i]))
1203 static bool ContainsTypeParameter (TypeSpec tparam, TypeSpec type)
1205 TypeSpec[] targs = type.TypeArguments;
1206 for (int i = 0; i < targs.Length; i++) {
1207 if (tparam == targs[i])
1210 if (ContainsTypeParameter (tparam, targs[i]))
1218 /// Check whether `a' and `b' may become equal generic types.
1219 /// The algorithm to do that is a little bit complicated.
1221 static bool MayBecomeEqualGenericTypes (TypeSpec a, TypeSpec b)
1223 if (a.IsGenericParameter) {
1225 // If a is an array of a's type, they may never
1232 // If b is a generic parameter or an actual type,
1233 // they may become equal:
1235 // class X<T,U> : I<T>, I<U>
1236 // class X<T> : I<T>, I<float>
1238 if (b.IsGenericParameter)
1239 return a != b && a.DeclaringType == b.DeclaringType;
1242 // We're now comparing a type parameter with a
1243 // generic instance. They may become equal unless
1244 // the type parameter appears anywhere in the
1245 // generic instance:
1247 // class X<T,U> : I<T>, I<X<U>>
1248 // -> error because you could instanciate it as
1251 // class X<T> : I<T>, I<X<T>> -> ok
1254 return !ContainsTypeParameter (a, b);
1257 if (b.IsGenericParameter)
1258 return MayBecomeEqualGenericTypes (b, a);
1261 // At this point, neither a nor b are a type parameter.
1263 // If one of them is a generic instance, compare them (if the
1264 // other one is not a generic instance, they can never
1267 if (TypeManager.IsGenericType (a) || TypeManager.IsGenericType (b))
1268 return IsEqual (a, b);
1271 // If both of them are arrays.
1273 var a_ac = a as ArrayContainer;
1275 var b_ac = b as ArrayContainer;
1276 if (b_ac == null || a_ac.Rank != b_ac.Rank)
1279 return MayBecomeEqualGenericTypes (a_ac.Element, b_ac.Element);
1283 // Ok, two ordinary types.
1289 public static bool Equals (TypeSpec[] x, TypeSpec[] y)
1294 if (x.Length != y.Length)
1297 for (int i = 0; i < x.Length; ++i)
1298 if (!IsEqual (x[i], y[i]))
1305 // Identity type conversion
1307 // Default reference comparison, it has to be used when comparing
1308 // two possible dynamic/internal types
1310 public static bool IsEqual (TypeSpec a, TypeSpec b)
1313 // This also rejects dynamic == dynamic
1314 return a.Kind != MemberKind.InternalCompilerType || a.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
1317 if (a == null || b == null)
1321 var a_a = (ArrayContainer) a;
1322 var b_a = b as ArrayContainer;
1326 return a_a.Rank == b_a.Rank && IsEqual (a_a.Element, b_a.Element);
1329 if (!a.IsGeneric || !b.IsGeneric) {
1331 // object and dynamic are considered equivalent there is an identity conversion
1332 // between object and dynamic, and between constructed types that are the same
1333 // when replacing all occurences of dynamic with object.
1335 if (a.BuiltinType == BuiltinTypeSpec.Type.Dynamic || b.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1336 return b.BuiltinType == BuiltinTypeSpec.Type.Object || a.BuiltinType == BuiltinTypeSpec.Type.Object;
1341 if (a.MemberDefinition != b.MemberDefinition)
1345 if (!Equals (a.TypeArguments, b.TypeArguments))
1348 a = a.DeclaringType;
1349 b = b.DeclaringType;
1350 } while (a != null);
1356 public interface ITypeDefinition : IMemberDefinition
1358 IAssemblyDefinition DeclaringAssembly { get; }
1359 string Namespace { get; }
1360 bool IsPartial { get; }
1361 bool IsComImport { get; }
1362 bool IsTypeForwarder { get; }
1363 int TypeParametersCount { get; }
1364 TypeParameterSpec[] TypeParameters { get; }
1366 TypeSpec GetAttributeCoClass ();
1367 string GetAttributeDefaultMember ();
1368 AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa);
1369 bool IsInternalAsPublic (IAssemblyDefinition assembly);
1370 void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache);
1373 class InternalType : TypeSpec, ITypeDefinition
1375 public static readonly InternalType AnonymousMethod = new InternalType ("anonymous method");
1376 public static readonly InternalType Arglist = new InternalType ("__arglist");
1377 public static readonly InternalType MethodGroup = new InternalType ("method group");
1378 public static readonly InternalType NullLiteral = new InternalType ("null");
1379 public static readonly InternalType FakeInternalType = new InternalType ("<fake$type>");
1380 public static readonly InternalType Namespace = new InternalType ("<namespace>");
1381 public static readonly InternalType ErrorType = new InternalType ("<error>");
1383 readonly string name;
1385 InternalType (string name)
1386 : base (MemberKind.InternalCompilerType, null, null, null, Modifiers.PUBLIC)
1389 this.definition = this;
1390 cache = MemberCache.Empty;
1392 // Make all internal types CLS-compliant, non-obsolete
1393 state = (state & ~(StateFlags.CLSCompliant_Undetected | StateFlags.Obsolete_Undetected | StateFlags.MissingDependency_Undetected)) | StateFlags.CLSCompliant;
1398 public override int Arity {
1404 IAssemblyDefinition ITypeDefinition.DeclaringAssembly {
1406 throw new NotImplementedException ();
1410 bool ITypeDefinition.IsComImport {
1416 bool IMemberDefinition.IsImported {
1422 bool ITypeDefinition.IsPartial {
1428 bool ITypeDefinition.IsTypeForwarder {
1434 public override string Name {
1440 string ITypeDefinition.Namespace {
1446 int ITypeDefinition.TypeParametersCount {
1452 TypeParameterSpec[] ITypeDefinition.TypeParameters {
1460 public override string GetSignatureForError ()
1465 #region ITypeDefinition Members
1467 TypeSpec ITypeDefinition.GetAttributeCoClass ()
1472 string ITypeDefinition.GetAttributeDefaultMember ()
1477 AttributeUsageAttribute ITypeDefinition.GetAttributeUsage (PredefinedAttribute pa)
1482 bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly)
1484 throw new NotImplementedException ();
1487 void ITypeDefinition.LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
1489 throw new NotImplementedException ();
1492 string[] IMemberDefinition.ConditionalConditions ()
1497 ObsoleteAttribute IMemberDefinition.GetAttributeObsolete ()
1502 bool? IMemberDefinition.CLSAttributeValue {
1508 void IMemberDefinition.SetIsAssigned ()
1512 void IMemberDefinition.SetIsUsed ()
1520 // Common base class for composite types
1522 public abstract class ElementTypeSpec : TypeSpec, ITypeDefinition
1524 protected ElementTypeSpec (MemberKind kind, TypeSpec element, MetaType info)
1525 : base (kind, element.DeclaringType, null, info, element.Modifiers)
1527 this.Element = element;
1529 state &= ~SharedStateFlags;
1530 state |= (element.state & SharedStateFlags);
1532 if (element.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1533 state |= StateFlags.HasDynamicElement;
1535 // Has to use its own type definition instead of just element definition to
1536 // correctly identify itself for cases like x.MemberDefininition == predefined.MemberDefinition
1537 this.definition = this;
1539 cache = MemberCache.Empty;
1544 public TypeSpec Element { get; private set; }
1546 bool ITypeDefinition.IsComImport {
1552 bool ITypeDefinition.IsPartial {
1558 bool ITypeDefinition.IsTypeForwarder {
1564 public override string Name {
1566 throw new NotSupportedException ();
1572 public override ObsoleteAttribute GetAttributeObsolete ()
1574 return Element.GetAttributeObsolete ();
1577 protected virtual string GetPostfixSignature ()
1582 public override string GetSignatureForDocumentation ()
1584 return Element.GetSignatureForDocumentation () + GetPostfixSignature ();
1587 public override string GetSignatureForError ()
1589 return Element.GetSignatureForError () + GetPostfixSignature ();
1592 public override TypeSpec Mutate (TypeParameterMutator mutator)
1594 var me = Element.Mutate (mutator);
1598 var mutated = (ElementTypeSpec) MemberwiseClone ();
1599 mutated.Element = me;
1600 mutated.info = null;
1604 #region ITypeDefinition Members
1606 IAssemblyDefinition ITypeDefinition.DeclaringAssembly {
1608 return Element.MemberDefinition.DeclaringAssembly;
1612 bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly)
1614 return Element.MemberDefinition.IsInternalAsPublic (assembly);
1617 public string Namespace {
1618 get { throw new NotImplementedException (); }
1621 public int TypeParametersCount {
1627 public TypeParameterSpec[] TypeParameters {
1629 throw new NotSupportedException ();
1633 public TypeSpec GetAttributeCoClass ()
1635 return Element.MemberDefinition.GetAttributeCoClass ();
1638 public string GetAttributeDefaultMember ()
1640 return Element.MemberDefinition.GetAttributeDefaultMember ();
1643 public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
1645 Element.MemberDefinition.LoadMembers (declaringType, onlyTypes, ref cache);
1648 public bool IsImported {
1650 return Element.MemberDefinition.IsImported;
1654 public string[] ConditionalConditions ()
1656 return Element.MemberDefinition.ConditionalConditions ();
1659 bool? IMemberDefinition.CLSAttributeValue {
1661 return Element.MemberDefinition.CLSAttributeValue;
1665 public void SetIsAssigned ()
1667 Element.MemberDefinition.SetIsAssigned ();
1670 public void SetIsUsed ()
1672 Element.MemberDefinition.SetIsUsed ();
1678 public class ArrayContainer : ElementTypeSpec
1680 public struct TypeRankPair : IEquatable<TypeRankPair>
1685 public TypeRankPair (TypeSpec ts, int rank)
1691 public override int GetHashCode ()
1693 return ts.GetHashCode () ^ rank.GetHashCode ();
1696 #region IEquatable<Tuple<T1,T2>> Members
1698 public bool Equals (TypeRankPair other)
1700 return other.ts == ts && other.rank == rank;
1707 readonly ModuleContainer module;
1709 private ArrayContainer (ModuleContainer module, TypeSpec element, int rank)
1710 : base (MemberKind.ArrayType, element, null)
1712 this.module = module;
1722 public MethodInfo GetConstructor ()
1724 var mb = module.Builder;
1726 var arg_types = new MetaType[rank];
1727 for (int i = 0; i < rank; i++)
1728 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1730 var ctor = mb.GetArrayMethod (
1731 GetMetaInfo (), Constructor.ConstructorName,
1732 CallingConventions.HasThis,
1738 public MethodInfo GetAddressMethod ()
1740 var mb = module.Builder;
1742 var arg_types = new MetaType[rank];
1743 for (int i = 0; i < rank; i++)
1744 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1746 var address = mb.GetArrayMethod (
1747 GetMetaInfo (), "Address",
1748 CallingConventions.HasThis | CallingConventions.Standard,
1749 ReferenceContainer.MakeType (module, Element).GetMetaInfo (), arg_types);
1754 public MethodInfo GetGetMethod ()
1756 var mb = module.Builder;
1758 var arg_types = new MetaType[rank];
1759 for (int i = 0; i < rank; i++)
1760 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1762 var get = mb.GetArrayMethod (
1763 GetMetaInfo (), "Get",
1764 CallingConventions.HasThis | CallingConventions.Standard,
1765 Element.GetMetaInfo (), arg_types);
1770 public MethodInfo GetSetMethod ()
1772 var mb = module.Builder;
1774 var arg_types = new MetaType[rank + 1];
1775 for (int i = 0; i < rank; i++)
1776 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1778 arg_types[rank] = Element.GetMetaInfo ();
1780 var set = mb.GetArrayMethod (
1781 GetMetaInfo (), "Set",
1782 CallingConventions.HasThis | CallingConventions.Standard,
1783 module.Compiler.BuiltinTypes.Void.GetMetaInfo (), arg_types);
1788 public override MetaType GetMetaInfo ()
1792 info = Element.GetMetaInfo ().MakeArrayType ();
1794 info = Element.GetMetaInfo ().MakeArrayType (rank);
1800 protected override string GetPostfixSignature()
1802 return GetPostfixSignature (rank);
1805 public static string GetPostfixSignature (int rank)
1807 StringBuilder sb = new StringBuilder ();
1809 for (int i = 1; i < rank; i++) {
1814 return sb.ToString ();
1817 public override string GetSignatureForDocumentation ()
1819 StringBuilder sb = new StringBuilder ();
1820 GetElementSignatureForDocumentation (sb);
1821 return sb.ToString ();
1824 void GetElementSignatureForDocumentation (StringBuilder sb)
1826 var ac = Element as ArrayContainer;
1828 sb.Append (Element.GetSignatureForDocumentation ());
1830 ac.GetElementSignatureForDocumentation (sb);
1833 for (int i = 1; i < rank; i++) {
1842 public static ArrayContainer MakeType (ModuleContainer module, TypeSpec element)
1844 return MakeType (module, element, 1);
1847 public static ArrayContainer MakeType (ModuleContainer module, TypeSpec element, int rank)
1850 var key = new TypeRankPair (element, rank);
1851 if (!module.ArrayTypesCache.TryGetValue (key, out ac)) {
1852 ac = new ArrayContainer (module, element, rank);
1853 ac.BaseType = module.Compiler.BuiltinTypes.Array;
1854 ac.Interfaces = ac.BaseType.Interfaces;
1856 module.ArrayTypesCache.Add (key, ac);
1863 class ReferenceContainer : ElementTypeSpec
1865 private ReferenceContainer (TypeSpec element)
1866 : base (MemberKind.Class, element, null) // TODO: Kind.Class is most likely wrong
1870 public override MetaType GetMetaInfo ()
1873 info = Element.GetMetaInfo ().MakeByRefType ();
1879 public static ReferenceContainer MakeType (ModuleContainer module, TypeSpec element)
1881 ReferenceContainer pc;
1882 if (!module.ReferenceTypesCache.TryGetValue (element, out pc)) {
1883 pc = new ReferenceContainer (element);
1884 module.ReferenceTypesCache.Add (element, pc);
1891 class PointerContainer : ElementTypeSpec
1893 private PointerContainer (TypeSpec element)
1894 : base (MemberKind.PointerType, element, null)
1896 // It's never CLS-Compliant
1897 state &= ~StateFlags.CLSCompliant_Undetected;
1900 public override MetaType GetMetaInfo ()
1903 info = Element.GetMetaInfo ().MakePointerType ();
1909 protected override string GetPostfixSignature()
1914 public static PointerContainer MakeType (ModuleContainer module, TypeSpec element)
1916 PointerContainer pc;
1917 if (!module.PointerTypesCache.TryGetValue (element, out pc)) {
1918 pc = new PointerContainer (element);
1919 module.PointerTypesCache.Add (element, pc);