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;
17 using MetaType = IKVM.Reflection.Type;
18 using IKVM.Reflection;
20 using MetaType = System.Type;
21 using System.Reflection;
27 // Inflated or non-inflated representation of any type.
29 public class TypeSpec : MemberSpec
31 protected MetaType info;
32 protected MemberCache cache;
33 protected IList<TypeSpec> ifaces;
36 Dictionary<TypeSpec[], InflatedTypeSpec> inflated_instances;
38 public static readonly TypeSpec[] EmptyTypes = new TypeSpec[0];
41 // Reflection Emit hacking
42 static readonly Type TypeBuilder;
43 static readonly Type GenericTypeBuilder;
47 var assembly = typeof (object).Assembly;
48 TypeBuilder = assembly.GetType ("System.Reflection.Emit.TypeBuilder");
49 GenericTypeBuilder = assembly.GetType ("System.Reflection.MonoGenericClass");
50 if (GenericTypeBuilder == null)
51 GenericTypeBuilder = assembly.GetType ("System.Reflection.Emit.TypeBuilderInstantiation");
55 public TypeSpec (MemberKind kind, TypeSpec declaringType, ITypeDefinition definition, MetaType info, Modifiers modifiers)
56 : base (kind, declaringType, definition, modifiers)
58 this.declaringType = declaringType;
61 if (definition != null && definition.TypeParametersCount > 0)
62 state |= StateFlags.IsGeneric;
67 public override int Arity {
69 return MemberDefinition.TypeParametersCount;
73 public virtual TypeSpec BaseType {
82 public virtual BuiltinTypeSpec.Type BuiltinType {
84 return BuiltinTypeSpec.Type.None;
88 public bool HasDynamicElement {
90 return (state & StateFlags.HasDynamicElement) != 0;
94 public virtual IList<TypeSpec> Interfaces {
103 public bool IsArray {
105 return Kind == MemberKind.ArrayType;
109 public bool IsAttribute {
116 if (type.BuiltinType == BuiltinTypeSpec.Type.Attribute)
122 type = type.base_type;
123 } while (type != null);
129 public bool IsInterface {
131 return Kind == MemberKind.Interface;
135 public bool IsClass {
137 return Kind == MemberKind.Class;
141 public bool IsConstantCompatible {
143 if ((Kind & (MemberKind.Enum | MemberKind.Class | MemberKind.Interface | MemberKind.Delegate | MemberKind.ArrayType)) != 0)
146 switch (BuiltinType) {
147 case BuiltinTypeSpec.Type.Int:
148 case BuiltinTypeSpec.Type.UInt:
149 case BuiltinTypeSpec.Type.Long:
150 case BuiltinTypeSpec.Type.ULong:
151 case BuiltinTypeSpec.Type.Float:
152 case BuiltinTypeSpec.Type.Double:
153 case BuiltinTypeSpec.Type.Char:
154 case BuiltinTypeSpec.Type.Short:
155 case BuiltinTypeSpec.Type.Decimal:
156 case BuiltinTypeSpec.Type.Bool:
157 case BuiltinTypeSpec.Type.SByte:
158 case BuiltinTypeSpec.Type.Byte:
159 case BuiltinTypeSpec.Type.UShort:
160 case BuiltinTypeSpec.Type.Dynamic:
168 public bool IsDelegate {
170 return Kind == MemberKind.Delegate;
175 // Returns true for instances of Expression<T>
177 public virtual bool IsExpressionTreeType {
182 state = value ? state | StateFlags.InflatedExpressionType : state & ~StateFlags.InflatedExpressionType;
188 return Kind == MemberKind.Enum;
193 // Returns true for instances of IList<T>, IEnumerable<T>, ICollection<T>
195 public virtual bool IsGenericIterateInterface {
200 state = value ? state | StateFlags.GenericIterateInterface : state & ~StateFlags.GenericIterateInterface;
205 // Returns true for instances of System.Threading.Tasks.Task<T>
207 public virtual bool IsGenericTask {
212 state = value ? state | StateFlags.GenericTask : state & ~StateFlags.GenericTask;
216 // TODO: Should probably do
217 // IsGenericType -- recursive
218 // HasTypeParameter -- non-recursive
219 public bool IsGenericOrParentIsGeneric {
225 ts = ts.declaringType;
226 } while (ts != null);
232 public bool IsGenericParameter {
234 return Kind == MemberKind.TypeParameter;
239 // Returns true for instances of Nullable<T>
241 public virtual bool IsNullableType {
246 state = value ? state | StateFlags.InflatedNullableType : state & ~StateFlags.InflatedNullableType;
250 public bool IsNested {
251 get { return declaringType != null && Kind != MemberKind.TypeParameter; }
254 public bool IsPointer {
256 return Kind == MemberKind.PointerType;
260 public bool IsSealed {
261 get { return (Modifiers & Modifiers.SEALED) != 0; }
264 public bool IsSpecialRuntimeType {
266 return (state & StateFlags.SpecialRuntimeType) != 0;
269 state = value ? state | StateFlags.SpecialRuntimeType : state & ~StateFlags.SpecialRuntimeType;
273 public bool IsStruct {
275 return Kind == MemberKind.Struct;
279 public bool IsTypeBuilder {
284 var meta = GetMetaInfo().GetType ();
285 return meta == TypeBuilder || meta == GenericTypeBuilder;
291 // Whether a type is unmanaged. This is used by the unsafe code
293 public bool IsUnmanaged {
296 return ((ElementTypeSpec) this).Element.IsUnmanaged;
298 var ds = MemberDefinition as TypeDefinition;
300 return ds.IsUnmanagedType ();
302 if (Kind == MemberKind.Void)
305 if (IsNested && DeclaringType.IsGenericOrParentIsGeneric)
308 return IsValueType (this);
313 // A cache of all type members (including nested types)
315 public MemberCache MemberCache {
317 if (cache == null || (state & StateFlags.PendingMemberCacheMembers) != 0)
318 InitializeMemberCache (false);
324 throw new InternalErrorException ("Membercache reset");
330 public MemberCache MemberCacheTypes {
333 InitializeMemberCache (true);
339 public new ITypeDefinition MemberDefinition {
341 return (ITypeDefinition) definition;
345 // TODO: Wouldn't be better to rely on cast to InflatedTypeSpec and
346 // remove the property, YES IT WOULD !!!
347 public virtual TypeSpec[] TypeArguments {
348 get { return TypeSpec.EmptyTypes; }
353 public bool AddInterface (TypeSpec iface)
355 if ((state & StateFlags.InterfacesExpanded) != 0)
356 throw new InternalErrorException ("Modifying expanded interface list");
358 if (ifaces == null) {
359 ifaces = new List<TypeSpec> () { iface };
363 if (!ifaces.Contains (iface)) {
372 // Special version used during type definition
374 public bool AddInterfaceDefined (TypeSpec iface)
376 if (!AddInterface (iface))
380 // We can get into a situation where a type is inflated before
381 // its interfaces are resoved. Consider this situation
383 // class A<T> : X<A<int>>, IFoo {}
385 // When resolving base class of X`1 we inflate context type A`1
386 // All this happens before we even hit IFoo resolve. Without
387 // additional expansion any inside usage of A<T> would miss IFoo
388 // interface because it comes from early inflated TypeSpec
390 if (inflated_instances != null) {
391 foreach (var inflated in inflated_instances) {
392 inflated.Value.AddInterface (iface);
400 // Returns all type arguments, usefull for nested types
402 public static TypeSpec[] GetAllTypeArguments (TypeSpec type)
404 IList<TypeSpec> targs = TypeSpec.EmptyTypes;
407 if (type.Arity > 0) {
408 if (targs.Count == 0) {
409 targs = type.TypeArguments;
411 var list = targs as List<TypeSpec> ?? new List<TypeSpec> (targs);
412 list.AddRange (type.TypeArguments);
417 type = type.declaringType;
418 } while (type != null);
420 return targs as TypeSpec[] ?? ((List<TypeSpec>) targs).ToArray ();
423 public AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa)
425 if (Kind != MemberKind.Class)
426 throw new InternalErrorException ();
429 return Attribute.DefaultUsageAttribute;
431 AttributeUsageAttribute aua = null;
433 while (type != null) {
434 aua = type.MemberDefinition.GetAttributeUsage (pa);
438 type = type.BaseType;
445 // Return metadata information used during emit to describe the type
447 public virtual MetaType GetMetaInfo ()
452 public virtual TypeSpec GetDefinition ()
458 // Text representation of type used by documentation writer
460 public override string GetSignatureForDocumentation ()
462 StringBuilder sb = new StringBuilder ();
464 sb.Append (DeclaringType.GetSignatureForDocumentation ());
466 sb.Append (MemberDefinition.Namespace);
474 if (this is InflatedTypeSpec) {
476 for (int i = 0; i < Arity; ++i) {
480 sb.Append (TypeArguments[i].GetSignatureForDocumentation ());
485 sb.Append (Arity.ToString ());
489 return sb.ToString ();
492 public string GetExplicitNameSignatureForDocumentation ()
494 StringBuilder sb = new StringBuilder ();
496 sb.Append (DeclaringType.GetExplicitNameSignatureForDocumentation ());
497 } else if (MemberDefinition.Namespace != null) {
498 sb.Append (MemberDefinition.Namespace.Replace ('.', '#'));
507 for (int i = 0; i < Arity; ++i) {
511 sb.Append (TypeArguments[i].GetExplicitNameSignatureForDocumentation ());
516 return sb.ToString ();
519 public override string GetSignatureForError ()
524 s = DeclaringType.GetSignatureForError ();
525 } else if (MemberDefinition is AnonymousTypeClass) {
526 return ((AnonymousTypeClass) MemberDefinition).GetSignatureForError ();
528 s = MemberDefinition.Namespace;
531 if (!string.IsNullOrEmpty (s))
534 return s + Name + GetTypeNameSignature ();
537 public string GetSignatureForErrorIncludingAssemblyName ()
539 return string.Format ("{0} [{1}]", GetSignatureForError (), MemberDefinition.DeclaringAssembly.FullName);
542 protected virtual string GetTypeNameSignature ()
547 return "<" + TypeManager.CSharpName (MemberDefinition.TypeParameters) + ">";
550 public bool ImplementsInterface (TypeSpec iface, bool variantly)
554 var ifaces = t.Interfaces;
555 if (ifaces != null) {
556 for (int i = 0; i < ifaces.Count; ++i) {
557 if (TypeSpecComparer.IsEqual (ifaces[i], iface))
560 if (variantly && TypeSpecComparer.Variant.IsEqual (ifaces[i], iface))
565 // TODO: Why is it needed when we do it during import
572 protected virtual void InitializeMemberCache (bool onlyTypes)
575 MemberDefinition.LoadMembers (this, onlyTypes, ref cache);
576 } catch (Exception e) {
577 throw new InternalErrorException (e, "Unexpected error when loading type `{0}'", GetSignatureForError ());
581 state |= StateFlags.PendingMemberCacheMembers;
583 state &= ~StateFlags.PendingMemberCacheMembers;
587 // Is @baseClass base implementation of @type. With enabled @dynamicIsEqual the slower
588 // comparison is used to hide differences between `object' and `dynamic' for generic
589 // types. Should not be used for comparisons where G<object> != G<dynamic>
591 public static bool IsBaseClass (TypeSpec type, TypeSpec baseClass, bool dynamicIsObject)
593 if (dynamicIsObject && baseClass.IsGeneric) {
595 // Returns true for a hierarchies like this when passing baseClass of A<dynamic>
597 // class B : A<object> {}
599 type = type.BaseType;
600 while (type != null) {
601 if (TypeSpecComparer.IsEqual (type, baseClass))
604 type = type.BaseType;
610 while (type != null) {
611 type = type.BaseType;
612 if (type == baseClass)
619 public static bool IsReferenceType (TypeSpec t)
622 case MemberKind.TypeParameter:
623 return ((TypeParameterSpec) t).IsReferenceType;
624 case MemberKind.Struct:
625 case MemberKind.Enum:
626 case MemberKind.Void:
628 case MemberKind.InternalCompilerType:
630 // Null is considered to be a reference type
632 return t == InternalType.NullLiteral || t.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
638 public static bool IsValueType (TypeSpec t)
641 case MemberKind.TypeParameter:
642 return ((TypeParameterSpec) t).IsValueType;
643 case MemberKind.Struct:
644 case MemberKind.Enum:
651 public override MemberSpec InflateMember (TypeParameterInflator inflator)
653 var targs = IsGeneric ? MemberDefinition.TypeParameters : TypeSpec.EmptyTypes;
656 // When inflating nested type from inside the type instance will be same
657 // because type parameters are same for all nested types
659 if (DeclaringType == inflator.TypeInstance) {
660 return MakeGenericType (inflator.Context, targs);
663 return new InflatedTypeSpec (inflator.Context, this, inflator.TypeInstance, targs);
667 // Inflates current type using specific type arguments
669 public InflatedTypeSpec MakeGenericType (IModuleContext context, TypeSpec[] targs)
671 if (targs.Length == 0 && !IsNested)
672 throw new ArgumentException ("Empty type arguments for type " + GetSignatureForError ());
674 InflatedTypeSpec instance;
676 if (inflated_instances == null) {
677 inflated_instances = new Dictionary<TypeSpec[], InflatedTypeSpec> (TypeSpecComparer.Default);
680 instance = this as InflatedTypeSpec;
681 if (instance != null) {
683 // Nested types could be inflated on already inflated instances
684 // Caching this type ensured we are using same instance for
685 // inside/outside inflation using local type parameters
687 inflated_instances.Add (TypeArguments, instance);
692 if (!inflated_instances.TryGetValue (targs, out instance)) {
693 if (GetDefinition () != this && !IsNested)
694 throw new InternalErrorException ("`{0}' must be type definition or nested non-inflated type to MakeGenericType",
695 GetSignatureForError ());
697 instance = new InflatedTypeSpec (context, this, declaringType, targs);
698 inflated_instances.Add (targs, instance);
704 public virtual TypeSpec Mutate (TypeParameterMutator mutator)
709 public override List<TypeSpec> ResolveMissingDependencies ()
711 List<TypeSpec> missing = null;
713 if (Kind == MemberKind.MissingType) {
714 missing = new List<TypeSpec> ();
719 foreach (var targ in TypeArguments) {
720 if (targ.Kind == MemberKind.MissingType) {
722 missing = new List<TypeSpec> ();
728 if (Interfaces != null) {
729 foreach (var iface in Interfaces) {
730 if (iface.Kind == MemberKind.MissingType) {
732 missing = new List<TypeSpec> ();
739 if (MemberDefinition.TypeParametersCount > 0) {
740 foreach (var tp in MemberDefinition.TypeParameters) {
741 var tp_missing = tp.GetMissingDependencies ();
742 if (tp_missing != null) {
744 missing = new List<TypeSpec> ();
746 missing.AddRange (tp_missing);
751 if (missing != null || BaseType == null)
754 return BaseType.ResolveMissingDependencies ();
757 public void SetMetaInfo (MetaType info)
759 if (this.info != null)
760 throw new InternalErrorException ("MetaInfo reset");
765 public void SetExtensionMethodContainer ()
767 modifiers |= Modifiers.METHOD_EXTENSION;
772 // Special version used for types which must exist in corlib or
773 // the compiler cannot work
775 public sealed class BuiltinTypeSpec : TypeSpec
781 // Ordered carefully for fast compares
809 MulticastDelegate = 23,
822 readonly string name;
824 public BuiltinTypeSpec (MemberKind kind, string ns, string name, Type builtinKind)
825 : base (kind, null, null, null, Modifiers.PUBLIC)
827 this.type = builtinKind;
832 public BuiltinTypeSpec (string name, Type builtinKind)
833 : this (MemberKind.InternalCompilerType, "", name, builtinKind)
835 // Make all internal types CLS-compliant, non-obsolete, compact
836 state = (state & ~(StateFlags.CLSCompliant_Undetected | StateFlags.Obsolete_Undetected | StateFlags.MissingDependency_Undetected)) | StateFlags.CLSCompliant;
841 public override int Arity {
847 public override BuiltinTypeSpec.Type BuiltinType {
853 public string FullName {
855 return ns + '.' + name;
859 public override string Name {
865 public string Namespace {
873 public static bool IsPrimitiveType (TypeSpec type)
875 return type.BuiltinType >= Type.FirstPrimitive && type.BuiltinType <= Type.LastPrimitive;
878 public static bool IsPrimitiveTypeOrDecimal (TypeSpec type)
880 return type.BuiltinType >= Type.FirstPrimitive && type.BuiltinType <= Type.Decimal;
883 public override string GetSignatureForError ()
886 case "Int32": return "int";
887 case "Int64": return "long";
888 case "String": return "string";
889 case "Boolean": return "bool";
890 case "Void": return "void";
891 case "Object": return "object";
892 case "UInt32": return "uint";
893 case "Int16": return "short";
894 case "UInt16": return "ushort";
895 case "UInt64": return "ulong";
896 case "Single": return "float";
897 case "Double": return "double";
898 case "Decimal": return "decimal";
899 case "Char": return "char";
900 case "Byte": return "byte";
901 case "SByte": return "sbyte";
911 // Returns the size of type if known, otherwise, 0
913 public static int GetSize (TypeSpec type)
915 switch (type.BuiltinType) {
939 public void SetDefinition (ITypeDefinition td, MetaType type, Modifiers mod)
941 this.definition = td;
943 this.modifiers |= (mod & ~Modifiers.AccessibilityMask);
946 public void SetDefinition (TypeSpec ts)
948 this.definition = ts.MemberDefinition;
949 this.info = ts.GetMetaInfo ();
950 this.BaseType = ts.BaseType;
951 this.Interfaces = ts.Interfaces;
952 this.modifiers = ts.Modifiers;
957 // Various type comparers used by compiler
959 static class TypeSpecComparer
962 // Does strict reference comparion only
964 public static readonly DefaultImpl Default = new DefaultImpl ();
966 public class DefaultImpl : IEqualityComparer<TypeSpec[]>
968 #region IEqualityComparer<TypeSpec[]> Members
970 bool IEqualityComparer<TypeSpec[]>.Equals (TypeSpec[] x, TypeSpec[] y)
975 if (x.Length != y.Length)
978 for (int i = 0; i < x.Length; ++i)
985 int IEqualityComparer<TypeSpec[]>.GetHashCode (TypeSpec[] obj)
988 for (int i = 0; i < obj.Length; ++i)
989 hash = (hash << 5) - hash + obj[i].GetHashCode ();
998 // When comparing type signature of overrides or overloads
999 // this version tolerates different MVARs at same position
1001 public static class Override
1003 public static bool IsEqual (TypeSpec a, TypeSpec b)
1009 // Consider the following example:
1011 // public abstract class A
1013 // public abstract T Foo<T>();
1016 // public class B : A
1018 // public override U Foo<T>() { return default (U); }
1021 // Here, `T' and `U' are method type parameters from different methods
1022 // (A.Foo and B.Foo), so both `==' and Equals() will fail.
1024 // However, since we're determining whether B.Foo() overrides A.Foo(),
1025 // we need to do a signature based comparision and consider them equal.
1028 var tp_a = a as TypeParameterSpec;
1030 var tp_b = b as TypeParameterSpec;
1031 return tp_b != null && tp_a.IsMethodOwned == tp_b.IsMethodOwned && tp_a.DeclaredPosition == tp_b.DeclaredPosition;
1034 var ac_a = a as ArrayContainer;
1036 var ac_b = b as ArrayContainer;
1037 return ac_b != null && ac_a.Rank == ac_b.Rank && IsEqual (ac_a.Element, ac_b.Element);
1040 if (a.BuiltinType == BuiltinTypeSpec.Type.Dynamic || b.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1041 return b.BuiltinType == BuiltinTypeSpec.Type.Object || a.BuiltinType == BuiltinTypeSpec.Type.Object;
1043 if (a.MemberDefinition != b.MemberDefinition)
1047 for (int i = 0; i < a.TypeArguments.Length; ++i) {
1048 if (!IsEqual (a.TypeArguments[i], b.TypeArguments[i]))
1052 a = a.DeclaringType;
1053 b = b.DeclaringType;
1054 } while (a != null);
1060 // Compares unordered arrays
1062 public static bool IsSame (TypeSpec[] a, TypeSpec[] b)
1067 if (a == null || b == null || a.Length != b.Length)
1070 for (int ai = 0; ai < a.Length; ++ai) {
1072 for (int bi = 0; bi < b.Length; ++bi) {
1073 if (IsEqual (a[ai], b[bi])) {
1086 public static bool IsEqual (AParametersCollection a, AParametersCollection b)
1091 if (a.Count != b.Count)
1094 for (int i = 0; i < a.Count; ++i) {
1095 if (!IsEqual (a.Types[i], b.Types[i]))
1098 if ((a.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (b.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
1107 // Type variance equality comparison
1109 public static class Variant
1111 public static bool IsEqual (TypeSpec type1, TypeSpec type2)
1113 if (!type1.IsGeneric || !type2.IsGeneric)
1116 var target_type_def = type2.MemberDefinition;
1117 if (type1.MemberDefinition != target_type_def)
1120 var t1_targs = type1.TypeArguments;
1121 var t2_targs = type2.TypeArguments;
1122 var targs_definition = target_type_def.TypeParameters;
1124 if (!type1.IsInterface && !type1.IsDelegate) {
1128 for (int i = 0; i < targs_definition.Length; ++i) {
1129 if (TypeSpecComparer.IsEqual (t1_targs[i], t2_targs[i]))
1132 Variance v = targs_definition[i].Variance;
1133 if (v == Variance.None) {
1137 if (v == Variance.Covariant) {
1138 if (!Convert.ImplicitReferenceConversionExists (t1_targs[i], t2_targs[i]))
1140 } else if (!Convert.ImplicitReferenceConversionExists (t2_targs[i], t1_targs[i])) {
1150 // Checks whether two generic instances may become equal for some
1151 // particular instantiation (26.3.1).
1153 public static class Unify
1156 // Either @a or @b must be generic type
1158 public static bool IsEqual (TypeSpec a, TypeSpec b)
1160 if (a.MemberDefinition != b.MemberDefinition) {
1161 var base_ifaces = a.Interfaces;
1162 if (base_ifaces != null) {
1163 foreach (var base_iface in base_ifaces) {
1164 if (base_iface.Arity > 0 && IsEqual (base_iface, b))
1172 var ta = a.TypeArguments;
1173 var tb = b.TypeArguments;
1174 for (int i = 0; i < ta.Length; i++) {
1175 if (!MayBecomeEqualGenericTypes (ta[i], tb[i]))
1182 static bool ContainsTypeParameter (TypeSpec tparam, TypeSpec type)
1184 TypeSpec[] targs = type.TypeArguments;
1185 for (int i = 0; i < targs.Length; i++) {
1186 if (tparam == targs[i])
1189 if (ContainsTypeParameter (tparam, targs[i]))
1197 /// Check whether `a' and `b' may become equal generic types.
1198 /// The algorithm to do that is a little bit complicated.
1200 static bool MayBecomeEqualGenericTypes (TypeSpec a, TypeSpec b)
1202 if (a.IsGenericParameter) {
1204 // If a is an array of a's type, they may never
1211 // If b is a generic parameter or an actual type,
1212 // they may become equal:
1214 // class X<T,U> : I<T>, I<U>
1215 // class X<T> : I<T>, I<float>
1217 if (b.IsGenericParameter)
1218 return a != b && a.DeclaringType == b.DeclaringType;
1221 // We're now comparing a type parameter with a
1222 // generic instance. They may become equal unless
1223 // the type parameter appears anywhere in the
1224 // generic instance:
1226 // class X<T,U> : I<T>, I<X<U>>
1227 // -> error because you could instanciate it as
1230 // class X<T> : I<T>, I<X<T>> -> ok
1233 return !ContainsTypeParameter (a, b);
1236 if (b.IsGenericParameter)
1237 return MayBecomeEqualGenericTypes (b, a);
1240 // At this point, neither a nor b are a type parameter.
1242 // If one of them is a generic instance, compare them (if the
1243 // other one is not a generic instance, they can never
1246 if (TypeManager.IsGenericType (a) || TypeManager.IsGenericType (b))
1247 return IsEqual (a, b);
1250 // If both of them are arrays.
1252 var a_ac = a as ArrayContainer;
1254 var b_ac = b as ArrayContainer;
1255 if (b_ac == null || a_ac.Rank != b_ac.Rank)
1258 return MayBecomeEqualGenericTypes (a_ac.Element, b_ac.Element);
1262 // Ok, two ordinary types.
1268 public static bool Equals (TypeSpec[] x, TypeSpec[] y)
1273 if (x.Length != y.Length)
1276 for (int i = 0; i < x.Length; ++i)
1277 if (!IsEqual (x[i], y[i]))
1284 // Identity type conversion
1286 // Default reference comparison, it has to be used when comparing
1287 // two possible dynamic/internal types
1289 public static bool IsEqual (TypeSpec a, TypeSpec b)
1292 // This also rejects dynamic == dynamic
1293 return a.Kind != MemberKind.InternalCompilerType || a.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
1296 if (a == null || b == null)
1300 var a_a = (ArrayContainer) a;
1301 var b_a = b as ArrayContainer;
1305 return a_a.Rank == b_a.Rank && IsEqual (a_a.Element, b_a.Element);
1308 if (!a.IsGeneric || !b.IsGeneric) {
1310 // object and dynamic are considered equivalent there is an identity conversion
1311 // between object and dynamic, and between constructed types that are the same
1312 // when replacing all occurences of dynamic with object.
1314 if (a.BuiltinType == BuiltinTypeSpec.Type.Dynamic || b.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1315 return b.BuiltinType == BuiltinTypeSpec.Type.Object || a.BuiltinType == BuiltinTypeSpec.Type.Object;
1320 if (a.MemberDefinition != b.MemberDefinition)
1324 if (!Equals (a.TypeArguments, b.TypeArguments))
1327 a = a.DeclaringType;
1328 b = b.DeclaringType;
1329 } while (a != null);
1335 public interface ITypeDefinition : IMemberDefinition
1337 IAssemblyDefinition DeclaringAssembly { get; }
1338 string Namespace { get; }
1339 bool IsPartial { get; }
1340 int TypeParametersCount { get; }
1341 TypeParameterSpec[] TypeParameters { get; }
1343 TypeSpec GetAttributeCoClass ();
1344 string GetAttributeDefaultMember ();
1345 AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa);
1346 bool IsInternalAsPublic (IAssemblyDefinition assembly);
1347 void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache);
1350 class InternalType : TypeSpec, ITypeDefinition
1352 public static readonly InternalType AnonymousMethod = new InternalType ("anonymous method");
1353 public static readonly InternalType Arglist = new InternalType ("__arglist");
1354 public static readonly InternalType MethodGroup = new InternalType ("method group");
1355 public static readonly InternalType NullLiteral = new InternalType ("null");
1356 public static readonly InternalType FakeInternalType = new InternalType ("<fake$type>");
1357 public static readonly InternalType Namespace = new InternalType ("<namespace>");
1358 public static readonly InternalType ErrorType = new InternalType ("<error>");
1360 readonly string name;
1362 InternalType (string name)
1363 : base (MemberKind.InternalCompilerType, null, null, null, Modifiers.PUBLIC)
1366 this.definition = this;
1367 cache = MemberCache.Empty;
1369 // Make all internal types CLS-compliant, non-obsolete
1370 state = (state & ~(StateFlags.CLSCompliant_Undetected | StateFlags.Obsolete_Undetected | StateFlags.MissingDependency_Undetected)) | StateFlags.CLSCompliant;
1375 public override int Arity {
1381 IAssemblyDefinition ITypeDefinition.DeclaringAssembly {
1383 throw new NotImplementedException ();
1387 bool IMemberDefinition.IsImported {
1393 bool ITypeDefinition.IsPartial {
1399 public override string Name {
1405 string ITypeDefinition.Namespace {
1411 int ITypeDefinition.TypeParametersCount {
1417 TypeParameterSpec[] ITypeDefinition.TypeParameters {
1425 public override string GetSignatureForError ()
1430 #region ITypeDefinition Members
1432 TypeSpec ITypeDefinition.GetAttributeCoClass ()
1437 string ITypeDefinition.GetAttributeDefaultMember ()
1442 AttributeUsageAttribute ITypeDefinition.GetAttributeUsage (PredefinedAttribute pa)
1447 bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly)
1449 throw new NotImplementedException ();
1452 void ITypeDefinition.LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
1454 throw new NotImplementedException ();
1457 string[] IMemberDefinition.ConditionalConditions ()
1462 ObsoleteAttribute IMemberDefinition.GetAttributeObsolete ()
1467 bool? IMemberDefinition.CLSAttributeValue {
1473 void IMemberDefinition.SetIsAssigned ()
1477 void IMemberDefinition.SetIsUsed ()
1485 // Common base class for composite types
1487 public abstract class ElementTypeSpec : TypeSpec, ITypeDefinition
1489 protected ElementTypeSpec (MemberKind kind, TypeSpec element, MetaType info)
1490 : base (kind, element.DeclaringType, null, info, element.Modifiers)
1492 this.Element = element;
1494 state &= ~SharedStateFlags;
1495 state |= (element.state & SharedStateFlags);
1497 if (element.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1498 state |= StateFlags.HasDynamicElement;
1500 // Has to use its own type definition instead of just element definition to
1501 // correctly identify itself for cases like x.MemberDefininition == predefined.MemberDefinition
1502 this.definition = this;
1504 cache = MemberCache.Empty;
1509 public TypeSpec Element { get; private set; }
1511 bool ITypeDefinition.IsPartial {
1517 public override string Name {
1519 throw new NotSupportedException ();
1525 public override ObsoleteAttribute GetAttributeObsolete ()
1527 return Element.GetAttributeObsolete ();
1530 protected virtual string GetPostfixSignature ()
1535 public override string GetSignatureForDocumentation ()
1537 return Element.GetSignatureForDocumentation () + GetPostfixSignature ();
1540 public override string GetSignatureForError ()
1542 return Element.GetSignatureForError () + GetPostfixSignature ();
1545 public override TypeSpec Mutate (TypeParameterMutator mutator)
1547 var me = Element.Mutate (mutator);
1551 var mutated = (ElementTypeSpec) MemberwiseClone ();
1552 mutated.Element = me;
1553 mutated.info = null;
1557 #region ITypeDefinition Members
1559 IAssemblyDefinition ITypeDefinition.DeclaringAssembly {
1561 return Element.MemberDefinition.DeclaringAssembly;
1565 bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly)
1567 return Element.MemberDefinition.IsInternalAsPublic (assembly);
1570 public string Namespace {
1571 get { throw new NotImplementedException (); }
1574 public int TypeParametersCount {
1580 public TypeParameterSpec[] TypeParameters {
1582 throw new NotSupportedException ();
1586 public TypeSpec GetAttributeCoClass ()
1588 return Element.MemberDefinition.GetAttributeCoClass ();
1591 public string GetAttributeDefaultMember ()
1593 return Element.MemberDefinition.GetAttributeDefaultMember ();
1596 public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
1598 Element.MemberDefinition.LoadMembers (declaringType, onlyTypes, ref cache);
1601 public bool IsImported {
1603 return Element.MemberDefinition.IsImported;
1607 public string[] ConditionalConditions ()
1609 return Element.MemberDefinition.ConditionalConditions ();
1612 bool? IMemberDefinition.CLSAttributeValue {
1614 return Element.MemberDefinition.CLSAttributeValue;
1618 public void SetIsAssigned ()
1620 Element.MemberDefinition.SetIsAssigned ();
1623 public void SetIsUsed ()
1625 Element.MemberDefinition.SetIsUsed ();
1631 public class ArrayContainer : ElementTypeSpec
1633 public struct TypeRankPair : IEquatable<TypeRankPair>
1638 public TypeRankPair (TypeSpec ts, int rank)
1644 public override int GetHashCode ()
1646 return ts.GetHashCode () ^ rank.GetHashCode ();
1649 #region IEquatable<Tuple<T1,T2>> Members
1651 public bool Equals (TypeRankPair other)
1653 return other.ts == ts && other.rank == rank;
1660 readonly ModuleContainer module;
1662 private ArrayContainer (ModuleContainer module, TypeSpec element, int rank)
1663 : base (MemberKind.ArrayType, element, null)
1665 this.module = module;
1675 public MethodInfo GetConstructor ()
1677 var mb = module.Builder;
1679 var arg_types = new MetaType[rank];
1680 for (int i = 0; i < rank; i++)
1681 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1683 var ctor = mb.GetArrayMethod (
1684 GetMetaInfo (), Constructor.ConstructorName,
1685 CallingConventions.HasThis,
1691 public MethodInfo GetAddressMethod ()
1693 var mb = module.Builder;
1695 var arg_types = new MetaType[rank];
1696 for (int i = 0; i < rank; i++)
1697 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1699 var address = mb.GetArrayMethod (
1700 GetMetaInfo (), "Address",
1701 CallingConventions.HasThis | CallingConventions.Standard,
1702 ReferenceContainer.MakeType (module, Element).GetMetaInfo (), arg_types);
1707 public MethodInfo GetGetMethod ()
1709 var mb = module.Builder;
1711 var arg_types = new MetaType[rank];
1712 for (int i = 0; i < rank; i++)
1713 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1715 var get = mb.GetArrayMethod (
1716 GetMetaInfo (), "Get",
1717 CallingConventions.HasThis | CallingConventions.Standard,
1718 Element.GetMetaInfo (), arg_types);
1723 public MethodInfo GetSetMethod ()
1725 var mb = module.Builder;
1727 var arg_types = new MetaType[rank + 1];
1728 for (int i = 0; i < rank; i++)
1729 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1731 arg_types[rank] = Element.GetMetaInfo ();
1733 var set = mb.GetArrayMethod (
1734 GetMetaInfo (), "Set",
1735 CallingConventions.HasThis | CallingConventions.Standard,
1736 module.Compiler.BuiltinTypes.Void.GetMetaInfo (), arg_types);
1741 public override MetaType GetMetaInfo ()
1745 info = Element.GetMetaInfo ().MakeArrayType ();
1747 info = Element.GetMetaInfo ().MakeArrayType (rank);
1753 protected override string GetPostfixSignature()
1755 return GetPostfixSignature (rank);
1758 public static string GetPostfixSignature (int rank)
1760 StringBuilder sb = new StringBuilder ();
1762 for (int i = 1; i < rank; i++) {
1767 return sb.ToString ();
1770 public override string GetSignatureForDocumentation ()
1772 StringBuilder sb = new StringBuilder ();
1773 GetElementSignatureForDocumentation (sb);
1774 return sb.ToString ();
1777 void GetElementSignatureForDocumentation (StringBuilder sb)
1779 var ac = Element as ArrayContainer;
1781 sb.Append (Element.GetSignatureForDocumentation ());
1783 ac.GetElementSignatureForDocumentation (sb);
1786 for (int i = 1; i < rank; i++) {
1795 public static ArrayContainer MakeType (ModuleContainer module, TypeSpec element)
1797 return MakeType (module, element, 1);
1800 public static ArrayContainer MakeType (ModuleContainer module, TypeSpec element, int rank)
1803 var key = new TypeRankPair (element, rank);
1804 if (!module.ArrayTypesCache.TryGetValue (key, out ac)) {
1805 ac = new ArrayContainer (module, element, rank) {
1806 BaseType = module.Compiler.BuiltinTypes.Array
1809 module.ArrayTypesCache.Add (key, ac);
1816 class ReferenceContainer : ElementTypeSpec
1818 private ReferenceContainer (TypeSpec element)
1819 : base (MemberKind.Class, element, null) // TODO: Kind.Class is most likely wrong
1823 public override MetaType GetMetaInfo ()
1826 info = Element.GetMetaInfo ().MakeByRefType ();
1832 public static ReferenceContainer MakeType (ModuleContainer module, TypeSpec element)
1834 ReferenceContainer pc;
1835 if (!module.ReferenceTypesCache.TryGetValue (element, out pc)) {
1836 pc = new ReferenceContainer (element);
1837 module.ReferenceTypesCache.Add (element, pc);
1844 class PointerContainer : ElementTypeSpec
1846 private PointerContainer (TypeSpec element)
1847 : base (MemberKind.PointerType, element, null)
1849 // It's never CLS-Compliant
1850 state &= ~StateFlags.CLSCompliant_Undetected;
1853 public override MetaType GetMetaInfo ()
1856 info = Element.GetMetaInfo ().MakePointerType ();
1862 protected override string GetPostfixSignature()
1867 public static PointerContainer MakeType (ModuleContainer module, TypeSpec element)
1869 PointerContainer pc;
1870 if (!module.PointerTypesCache.TryGetValue (element, out pc)) {
1871 pc = new PointerContainer (element);
1872 module.PointerTypesCache.Add (element, pc);