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 {
101 if ((state & StateFlags.InterfacesImported) == 0) {
102 state |= StateFlags.InterfacesImported;
105 // Delay interfaces expansion to save memory and once all
106 // base types has been imported to avoid problems where
107 // interface references type before its base was imported
109 var imported = MemberDefinition as ImportedTypeDefinition;
110 if (imported != null && Kind != MemberKind.MissingType)
111 imported.DefineInterfaces (this);
122 public bool IsArray {
124 return Kind == MemberKind.ArrayType;
128 public bool IsAttribute {
135 if (type.BuiltinType == BuiltinTypeSpec.Type.Attribute)
141 type = type.base_type;
142 } while (type != null);
148 public bool IsInterface {
150 return Kind == MemberKind.Interface;
154 public bool IsClass {
156 return Kind == MemberKind.Class;
160 public bool IsConstantCompatible {
162 if ((Kind & (MemberKind.Enum | MemberKind.Class | MemberKind.Interface | MemberKind.Delegate | MemberKind.ArrayType)) != 0)
165 switch (BuiltinType) {
166 case BuiltinTypeSpec.Type.Int:
167 case BuiltinTypeSpec.Type.UInt:
168 case BuiltinTypeSpec.Type.Long:
169 case BuiltinTypeSpec.Type.ULong:
170 case BuiltinTypeSpec.Type.Float:
171 case BuiltinTypeSpec.Type.Double:
172 case BuiltinTypeSpec.Type.Char:
173 case BuiltinTypeSpec.Type.Short:
174 case BuiltinTypeSpec.Type.Decimal:
175 case BuiltinTypeSpec.Type.Bool:
176 case BuiltinTypeSpec.Type.SByte:
177 case BuiltinTypeSpec.Type.Byte:
178 case BuiltinTypeSpec.Type.UShort:
179 case BuiltinTypeSpec.Type.Dynamic:
187 public bool IsDelegate {
189 return Kind == MemberKind.Delegate;
194 // Returns true for instances of Expression<T>
196 public virtual bool IsExpressionTreeType {
201 state = value ? state | StateFlags.InflatedExpressionType : state & ~StateFlags.InflatedExpressionType;
207 return Kind == MemberKind.Enum;
212 // Returns true for instances of IList<T>, IEnumerable<T>, ICollection<T>
214 public virtual bool IsArrayGenericInterface {
219 state = value ? state | StateFlags.GenericIterateInterface : state & ~StateFlags.GenericIterateInterface;
224 // Returns true for instances of System.Threading.Tasks.Task<T>
226 public virtual bool IsGenericTask {
231 state = value ? state | StateFlags.GenericTask : state & ~StateFlags.GenericTask;
235 // TODO: Should probably do
236 // IsGenericType -- recursive
237 // HasTypeParameter -- non-recursive
238 public bool IsGenericOrParentIsGeneric {
244 ts = ts.declaringType;
245 } while (ts != null);
251 public bool IsGenericParameter {
253 return Kind == MemberKind.TypeParameter;
258 // Returns true for instances of Nullable<T>
260 public virtual bool IsNullableType {
265 state = value ? state | StateFlags.InflatedNullableType : state & ~StateFlags.InflatedNullableType;
269 public bool IsNested {
270 get { return declaringType != null && Kind != MemberKind.TypeParameter; }
273 public bool IsPointer {
275 return Kind == MemberKind.PointerType;
279 public bool IsSealed {
280 get { return (Modifiers & Modifiers.SEALED) != 0; }
283 public bool IsSpecialRuntimeType {
285 return (state & StateFlags.SpecialRuntimeType) != 0;
288 state = value ? state | StateFlags.SpecialRuntimeType : state & ~StateFlags.SpecialRuntimeType;
292 public bool IsStruct {
294 return Kind == MemberKind.Struct;
298 public bool IsStructOrEnum {
300 return (Kind & (MemberKind.Struct | MemberKind.Enum)) != 0;
304 public bool IsTypeBuilder {
309 var meta = GetMetaInfo().GetType ();
310 return meta == TypeBuilder || meta == GenericTypeBuilder;
316 // Whether a type is unmanaged. This is used by the unsafe code
318 public bool IsUnmanaged {
321 return ((ElementTypeSpec) this).Element.IsUnmanaged;
323 var ds = MemberDefinition as TypeDefinition;
325 return ds.IsUnmanagedType ();
327 if (Kind == MemberKind.Void)
330 if (Kind == MemberKind.TypeParameter)
333 if (IsNested && DeclaringType.IsGenericOrParentIsGeneric)
336 return IsValueType (this);
341 // A cache of all type members (including nested types)
343 public MemberCache MemberCache {
345 if (cache == null || (state & StateFlags.PendingMemberCacheMembers) != 0)
346 InitializeMemberCache (false);
352 throw new InternalErrorException ("Membercache reset");
358 public MemberCache MemberCacheTypes {
361 InitializeMemberCache (true);
367 public new ITypeDefinition MemberDefinition {
369 return (ITypeDefinition) definition;
373 // TODO: Wouldn't be better to rely on cast to InflatedTypeSpec and
374 // remove the property, YES IT WOULD !!!
375 public virtual TypeSpec[] TypeArguments {
376 get { return TypeSpec.EmptyTypes; }
381 public virtual bool AddInterface (TypeSpec iface)
383 if ((state & StateFlags.InterfacesExpanded) != 0)
384 throw new InternalErrorException ("Modifying expanded interface list");
386 if (ifaces == null) {
387 ifaces = new List<TypeSpec> { iface };
391 if (!ifaces.Contains (iface)) {
400 // Special version used during type definition
402 public bool AddInterfaceDefined (TypeSpec iface)
404 if (!AddInterface (iface))
408 // We can get into a situation where a type is inflated before
409 // its interfaces are resoved. Consider this situation
411 // class A<T> : X<A<int>>, IFoo {}
413 // When resolving base class of X`1 we inflate context type A`1
414 // All this happens before we even hit IFoo resolve. Without
415 // additional expansion any inside usage of A<T> would miss IFoo
416 // interface because it comes from early inflated A`1 definition.
418 if (inflated_instances != null) {
420 // Inflate only existing instances not any new instances added
421 // during AddInterface
423 var inflated_existing = inflated_instances.Values.ToArray ();
424 foreach (var inflated in inflated_existing) {
425 inflated.AddInterface (iface);
433 // Returns all type arguments, usefull for nested types
435 public static TypeSpec[] GetAllTypeArguments (TypeSpec type)
437 IList<TypeSpec> targs = TypeSpec.EmptyTypes;
440 if (type.Arity > 0) {
441 if (targs.Count == 0) {
442 targs = type.TypeArguments;
444 var list = targs as List<TypeSpec> ?? new List<TypeSpec> (targs);
445 list.AddRange (type.TypeArguments);
450 type = type.declaringType;
451 } while (type != null);
453 return targs as TypeSpec[] ?? ((List<TypeSpec>) targs).ToArray ();
456 public AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa)
458 if (Kind != MemberKind.Class)
459 throw new InternalErrorException ();
462 return Attribute.DefaultUsageAttribute;
464 AttributeUsageAttribute aua = null;
466 while (type != null) {
467 aua = type.MemberDefinition.GetAttributeUsage (pa);
471 type = type.BaseType;
478 // Return metadata information used during emit to describe the type
480 public virtual MetaType GetMetaInfo ()
485 public virtual TypeSpec GetDefinition ()
491 // Text representation of type used by documentation writer
493 public sealed override string GetSignatureForDocumentation ()
495 return GetSignatureForDocumentation (false);
498 public virtual string GetSignatureForDocumentation (bool explicitName)
500 StringBuilder sb = new StringBuilder ();
502 sb.Append (DeclaringType.GetSignatureForDocumentation (explicitName));
503 } else if (MemberDefinition.Namespace != null) {
504 sb.Append (explicitName ? MemberDefinition.Namespace.Replace ('.', '#') : MemberDefinition.Namespace);
508 sb.Append (explicitName ? "#" : ".");
512 if (this is InflatedTypeSpec) {
514 for (int i = 0; i < Arity; ++i) {
518 sb.Append (TypeArguments[i].GetSignatureForDocumentation (explicitName));
523 sb.Append (Arity.ToString ());
527 return sb.ToString ();
530 public override string GetSignatureForError ()
535 s = DeclaringType.GetSignatureForError ();
536 } else if (MemberDefinition is AnonymousTypeClass) {
537 return ((AnonymousTypeClass) MemberDefinition).GetSignatureForError ();
539 s = MemberDefinition.Namespace;
542 if (!string.IsNullOrEmpty (s))
545 return s + Name + GetTypeNameSignature ();
548 public string GetSignatureForErrorIncludingAssemblyName ()
550 var imported = MemberDefinition.DeclaringAssembly as ImportedAssemblyDefinition;
552 var location = imported != null ?
553 System.IO.Path.GetFullPath (imported.Location) :
554 ((MemberCore)MemberDefinition).Location.NameFullPath;
556 return string.Format ("{0} [{1} -- {2}]", GetSignatureForError (),
557 MemberDefinition.DeclaringAssembly.FullName,
561 protected virtual string GetTypeNameSignature ()
566 return "<" + TypeManager.CSharpName (MemberDefinition.TypeParameters) + ">";
569 public bool ImplementsInterface (TypeSpec iface, bool variantly)
571 var ifaces = Interfaces;
572 if (ifaces != null) {
573 for (int i = 0; i < ifaces.Count; ++i) {
574 if (TypeSpecComparer.IsEqual (ifaces[i], iface))
577 if (variantly && TypeSpecComparer.Variant.IsEqual (ifaces[i], iface))
585 protected virtual void InitializeMemberCache (bool onlyTypes)
588 MemberDefinition.LoadMembers (this, onlyTypes, ref cache);
589 } catch (Exception e) {
590 throw new InternalErrorException (e, "Unexpected error when loading type `{0}'", GetSignatureForError ());
594 state |= StateFlags.PendingMemberCacheMembers;
596 state &= ~StateFlags.PendingMemberCacheMembers;
600 // Is @baseClass base implementation of @type. With enabled @dynamicIsEqual the slower
601 // comparison is used to hide differences between `object' and `dynamic' for generic
602 // types. Should not be used for comparisons where G<object> != G<dynamic>
604 public static bool IsBaseClass (TypeSpec type, TypeSpec baseClass, bool dynamicIsObject)
606 if (dynamicIsObject && baseClass.IsGeneric) {
608 // Returns true for a hierarchies like this when passing baseClass of A<dynamic>
610 // class B : A<object> {}
612 type = type.BaseType;
613 while (type != null) {
614 if (TypeSpecComparer.IsEqual (type, baseClass))
617 type = type.BaseType;
623 while (type != null) {
624 type = type.BaseType;
625 if (type == baseClass)
632 public static bool IsReferenceType (TypeSpec t)
635 case MemberKind.TypeParameter:
636 return ((TypeParameterSpec) t).IsReferenceType;
637 case MemberKind.Struct:
638 case MemberKind.Enum:
639 case MemberKind.Void:
640 case MemberKind.PointerType:
642 case MemberKind.InternalCompilerType:
644 // Null is considered to be a reference type
646 return t == InternalType.NullLiteral || t.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
652 public static bool IsNonNullableValueType (TypeSpec t)
655 case MemberKind.TypeParameter:
656 return ((TypeParameterSpec) t).IsValueType;
657 case MemberKind.Struct:
658 return !t.IsNullableType;
659 case MemberKind.Enum:
666 public static bool IsValueType (TypeSpec t)
669 case MemberKind.TypeParameter:
670 return ((TypeParameterSpec) t).IsValueType;
671 case MemberKind.Struct:
672 case MemberKind.Enum:
679 public override MemberSpec InflateMember (TypeParameterInflator inflator)
681 var targs = IsGeneric ? MemberDefinition.TypeParameters : TypeSpec.EmptyTypes;
684 // When inflating nested type from inside the type instance will be same
685 // because type parameters are same for all nested types
687 if (DeclaringType == inflator.TypeInstance) {
688 return MakeGenericType (inflator.Context, targs);
691 return new InflatedTypeSpec (inflator.Context, this, inflator.TypeInstance, targs);
695 // Inflates current type using specific type arguments
697 public InflatedTypeSpec MakeGenericType (IModuleContext context, TypeSpec[] targs)
699 if (targs.Length == 0 && !IsNested)
700 throw new ArgumentException ("Empty type arguments for type " + GetSignatureForError ());
702 InflatedTypeSpec instance;
704 if (inflated_instances == null) {
705 inflated_instances = new Dictionary<TypeSpec[], InflatedTypeSpec> (TypeSpecComparer.Default);
708 instance = this as InflatedTypeSpec;
709 if (instance != null) {
711 // Nested types could be inflated on already inflated instances
712 // Caching this type ensured we are using same instance for
713 // inside/outside inflation using local type parameters
715 inflated_instances.Add (TypeArguments, instance);
720 if (!inflated_instances.TryGetValue (targs, out instance)) {
721 if (GetDefinition () != this && !IsNested)
722 throw new InternalErrorException ("`{0}' must be type definition or nested non-inflated type to MakeGenericType",
723 GetSignatureForError ());
725 instance = new InflatedTypeSpec (context, this, declaringType, targs);
726 inflated_instances.Add (targs, instance);
732 public virtual TypeSpec Mutate (TypeParameterMutator mutator)
737 public override List<MissingTypeSpecReference> ResolveMissingDependencies (MemberSpec caller)
739 List<MissingTypeSpecReference> missing = null;
741 if (Kind == MemberKind.MissingType) {
742 missing = new List<MissingTypeSpecReference> ();
743 missing.Add (new MissingTypeSpecReference (this, caller));
747 foreach (var targ in TypeArguments) {
748 if (targ.Kind == MemberKind.MissingType) {
750 missing = new List<MissingTypeSpecReference> ();
752 missing.Add (new MissingTypeSpecReference (targ, caller));
756 if (Interfaces != null) {
757 foreach (var iface in Interfaces) {
758 if (iface.Kind == MemberKind.MissingType) {
760 missing = new List<MissingTypeSpecReference> ();
762 missing.Add (new MissingTypeSpecReference (iface, caller));
767 if (MemberDefinition.TypeParametersCount > 0) {
768 foreach (var tp in MemberDefinition.TypeParameters) {
769 var tp_missing = tp.GetMissingDependencies (this);
770 if (tp_missing != null) {
772 missing = new List<MissingTypeSpecReference> ();
774 missing.AddRange (tp_missing);
779 if (missing != null || BaseType == null)
782 return BaseType.ResolveMissingDependencies (this);
785 public void SetMetaInfo (MetaType info)
787 if (this.info != null)
788 throw new InternalErrorException ("MetaInfo reset");
793 public void SetExtensionMethodContainer ()
795 modifiers |= Modifiers.METHOD_EXTENSION;
798 public void UpdateInflatedInstancesBaseType ()
801 // When nested class has a partial part the situation where parent type
802 // is inflated before its base type is defined can occur. In such case
803 // all inflated (should be only 1) instansted need to be updated
805 // partial class A<T> {
806 // partial class B : A<int> { }
809 // partial class A<T> : X {}
811 if (inflated_instances == null)
814 foreach (var inflated in inflated_instances) {
816 // Don't need to inflate possible generic type because for now the method
817 // is always used from within the nested type
819 inflated.Value.BaseType = base_type;
825 // Special version used for types which must exist in corlib or
826 // the compiler cannot work
828 public sealed class BuiltinTypeSpec : TypeSpec
834 // Ordered carefully for fast compares
862 MulticastDelegate = 23,
875 readonly string name;
877 public BuiltinTypeSpec (MemberKind kind, string ns, string name, Type builtinKind)
878 : base (kind, null, null, null, Modifiers.PUBLIC)
880 this.type = builtinKind;
885 public BuiltinTypeSpec (string name, Type builtinKind)
886 : this (MemberKind.InternalCompilerType, "", name, builtinKind)
888 // Make all internal types CLS-compliant, non-obsolete, compact
889 state = (state & ~(StateFlags.CLSCompliant_Undetected | StateFlags.Obsolete_Undetected | StateFlags.MissingDependency_Undetected)) | StateFlags.CLSCompliant;
894 public override int Arity {
900 public override BuiltinTypeSpec.Type BuiltinType {
906 public string FullName {
908 return ns + '.' + name;
912 public override string Name {
918 public string Namespace {
926 public static bool IsPrimitiveType (TypeSpec type)
928 return type.BuiltinType >= Type.FirstPrimitive && type.BuiltinType <= Type.LastPrimitive;
931 public static bool IsPrimitiveTypeOrDecimal (TypeSpec type)
933 return type.BuiltinType >= Type.FirstPrimitive && type.BuiltinType <= Type.Decimal;
936 public override string GetSignatureForError ()
939 case "Int32": return "int";
940 case "Int64": return "long";
941 case "String": return "string";
942 case "Boolean": return "bool";
943 case "Void": return "void";
944 case "Object": return "object";
945 case "UInt32": return "uint";
946 case "Int16": return "short";
947 case "UInt16": return "ushort";
948 case "UInt64": return "ulong";
949 case "Single": return "float";
950 case "Double": return "double";
951 case "Decimal": return "decimal";
952 case "Char": return "char";
953 case "Byte": return "byte";
954 case "SByte": return "sbyte";
964 // Returns the size of type if known, otherwise, 0
966 public static int GetSize (TypeSpec type)
968 switch (type.BuiltinType) {
992 public void SetDefinition (ITypeDefinition td, MetaType type, Modifiers mod)
994 this.definition = td;
996 this.modifiers |= (mod & ~Modifiers.AccessibilityMask);
999 public void SetDefinition (TypeSpec ts)
1001 this.definition = ts.MemberDefinition;
1002 this.info = ts.GetMetaInfo ();
1003 this.BaseType = ts.BaseType;
1004 this.Interfaces = ts.Interfaces;
1005 this.modifiers = ts.Modifiers;
1010 // Various type comparers used by compiler
1012 static class TypeSpecComparer
1015 // Does strict reference comparion only
1017 public static readonly DefaultImpl Default = new DefaultImpl ();
1019 public class DefaultImpl : IEqualityComparer<TypeSpec[]>
1021 #region IEqualityComparer<TypeSpec[]> Members
1023 bool IEqualityComparer<TypeSpec[]>.Equals (TypeSpec[] x, TypeSpec[] y)
1028 if (x.Length != y.Length)
1031 for (int i = 0; i < x.Length; ++i)
1038 int IEqualityComparer<TypeSpec[]>.GetHashCode (TypeSpec[] obj)
1041 for (int i = 0; i < obj.Length; ++i)
1042 hash = (hash << 5) - hash + obj[i].GetHashCode ();
1051 // When comparing type signature of overrides or overloads
1052 // this version tolerates different MVARs at same position
1054 public static class Override
1056 public static bool IsEqual (TypeSpec a, TypeSpec b)
1062 // Consider the following example:
1064 // public abstract class A
1066 // public abstract T Foo<T>();
1069 // public class B : A
1071 // public override U Foo<T>() { return default (U); }
1074 // Here, `T' and `U' are method type parameters from different methods
1075 // (A.Foo and B.Foo), so both `==' and Equals() will fail.
1077 // However, since we're determining whether B.Foo() overrides A.Foo(),
1078 // we need to do a signature based comparision and consider them equal.
1081 var tp_a = a as TypeParameterSpec;
1083 var tp_b = b as TypeParameterSpec;
1084 return tp_b != null && tp_a.IsMethodOwned == tp_b.IsMethodOwned && tp_a.DeclaredPosition == tp_b.DeclaredPosition;
1087 var ac_a = a as ArrayContainer;
1089 var ac_b = b as ArrayContainer;
1090 return ac_b != null && ac_a.Rank == ac_b.Rank && IsEqual (ac_a.Element, ac_b.Element);
1093 if (a.BuiltinType == BuiltinTypeSpec.Type.Dynamic || b.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1094 return b.BuiltinType == BuiltinTypeSpec.Type.Object || a.BuiltinType == BuiltinTypeSpec.Type.Object;
1096 if (a.MemberDefinition != b.MemberDefinition)
1100 for (int i = 0; i < a.TypeArguments.Length; ++i) {
1101 if (!IsEqual (a.TypeArguments[i], b.TypeArguments[i]))
1105 a = a.DeclaringType;
1106 b = b.DeclaringType;
1107 } while (a != null);
1112 public static bool IsEqual (TypeSpec[] a, TypeSpec[] b)
1117 if (a.Length != b.Length)
1120 for (int i = 0; i < a.Length; ++i) {
1121 if (!IsEqual (a[i], b[i]))
1130 // Compares unordered arrays
1132 public static bool IsSame (TypeSpec[] a, TypeSpec[] b)
1137 if (a == null || b == null || a.Length != b.Length)
1140 for (int ai = 0; ai < a.Length; ++ai) {
1142 for (int bi = 0; bi < b.Length; ++bi) {
1143 if (IsEqual (a[ai], b[bi])) {
1156 public static bool IsEqual (AParametersCollection a, AParametersCollection b)
1161 if (a.Count != b.Count)
1164 for (int i = 0; i < a.Count; ++i) {
1165 if (!IsEqual (a.Types[i], b.Types[i]))
1168 if ((a.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (b.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
1177 // Type variance equality comparison
1179 public static class Variant
1181 public static bool IsEqual (TypeSpec type1, TypeSpec type2)
1183 if (!type1.IsGeneric || !type2.IsGeneric)
1186 var target_type_def = type2.MemberDefinition;
1187 if (type1.MemberDefinition != target_type_def)
1190 var t1_targs = type1.TypeArguments;
1191 var t2_targs = type2.TypeArguments;
1192 var targs_definition = target_type_def.TypeParameters;
1194 if (!type1.IsInterface && !type1.IsDelegate) {
1198 for (int i = 0; i < targs_definition.Length; ++i) {
1199 if (TypeSpecComparer.IsEqual (t1_targs[i], t2_targs[i]))
1202 Variance v = targs_definition[i].Variance;
1203 if (v == Variance.None) {
1207 if (v == Variance.Covariant) {
1208 if (!Convert.ImplicitReferenceConversionExists (t1_targs[i], t2_targs[i]))
1210 } else if (!Convert.ImplicitReferenceConversionExists (t2_targs[i], t1_targs[i])) {
1220 // Checks whether two generic instances may become equal for some
1221 // particular instantiation (26.3.1).
1223 public static class Unify
1226 // Either @a or @b must be generic type
1228 public static bool IsEqual (TypeSpec a, TypeSpec b)
1230 if (a.MemberDefinition != b.MemberDefinition) {
1231 var base_ifaces = a.Interfaces;
1232 if (base_ifaces != null) {
1233 foreach (var base_iface in base_ifaces) {
1234 if (base_iface.Arity > 0 && IsEqual (base_iface, b))
1242 var ta = a.TypeArguments;
1243 var tb = b.TypeArguments;
1244 for (int i = 0; i < ta.Length; i++) {
1245 if (!MayBecomeEqualGenericTypes (ta[i], tb[i]))
1249 if (a.IsNested && b.IsNested)
1250 return IsEqual (a.DeclaringType, b.DeclaringType);
1255 static bool ContainsTypeParameter (TypeSpec tparam, TypeSpec type)
1257 TypeSpec[] targs = type.TypeArguments;
1258 for (int i = 0; i < targs.Length; i++) {
1259 if (tparam == targs[i])
1262 if (ContainsTypeParameter (tparam, targs[i]))
1270 /// Check whether `a' and `b' may become equal generic types.
1271 /// The algorithm to do that is a little bit complicated.
1273 static bool MayBecomeEqualGenericTypes (TypeSpec a, TypeSpec b)
1275 if (a.IsGenericParameter) {
1277 // If a is an array of a's type, they may never
1284 // If b is a generic parameter or an actual type,
1285 // they may become equal:
1287 // class X<T,U> : I<T>, I<U>
1288 // class X<T> : I<T>, I<float>
1290 if (b.IsGenericParameter)
1291 return a != b && a.DeclaringType == b.DeclaringType;
1294 // We're now comparing a type parameter with a
1295 // generic instance. They may become equal unless
1296 // the type parameter appears anywhere in the
1297 // generic instance:
1299 // class X<T,U> : I<T>, I<X<U>>
1300 // -> error because you could instanciate it as
1303 // class X<T> : I<T>, I<X<T>> -> ok
1306 return !ContainsTypeParameter (a, b);
1309 if (b.IsGenericParameter)
1310 return MayBecomeEqualGenericTypes (b, a);
1313 // At this point, neither a nor b are a type parameter.
1315 // If one of them is a generic instance, compare them (if the
1316 // other one is not a generic instance, they can never
1319 if (TypeManager.IsGenericType (a) || TypeManager.IsGenericType (b))
1320 return IsEqual (a, b);
1323 // If both of them are arrays.
1325 var a_ac = a as ArrayContainer;
1327 var b_ac = b as ArrayContainer;
1328 if (b_ac == null || a_ac.Rank != b_ac.Rank)
1331 return MayBecomeEqualGenericTypes (a_ac.Element, b_ac.Element);
1335 // Ok, two ordinary types.
1341 public static bool Equals (TypeSpec[] x, TypeSpec[] y)
1346 if (x.Length != y.Length)
1349 for (int i = 0; i < x.Length; ++i)
1350 if (!IsEqual (x[i], y[i]))
1357 // Identity type conversion
1359 // Default reference comparison, it has to be used when comparing
1360 // two possible dynamic/internal types
1362 public static bool IsEqual (TypeSpec a, TypeSpec b)
1365 // This also rejects dynamic == dynamic
1366 return a.Kind != MemberKind.InternalCompilerType || a.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
1369 if (a == null || b == null)
1373 var a_a = (ArrayContainer) a;
1374 var b_a = b as ArrayContainer;
1378 return a_a.Rank == b_a.Rank && IsEqual (a_a.Element, b_a.Element);
1381 if (!a.IsGeneric || !b.IsGeneric) {
1383 // object and dynamic are considered equivalent there is an identity conversion
1384 // between object and dynamic, and between constructed types that are the same
1385 // when replacing all occurences of dynamic with object.
1387 if (a.BuiltinType == BuiltinTypeSpec.Type.Dynamic || b.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1388 return b.BuiltinType == BuiltinTypeSpec.Type.Object || a.BuiltinType == BuiltinTypeSpec.Type.Object;
1393 if (a.MemberDefinition != b.MemberDefinition)
1397 if (!Equals (a.TypeArguments, b.TypeArguments))
1400 a = a.DeclaringType;
1401 b = b.DeclaringType;
1402 } while (a != null);
1408 public interface ITypeDefinition : IMemberDefinition
1410 IAssemblyDefinition DeclaringAssembly { get; }
1411 string Namespace { get; }
1412 bool IsPartial { get; }
1413 bool IsComImport { get; }
1414 bool IsTypeForwarder { get; }
1415 bool IsCyclicTypeForwarder { get; }
1416 int TypeParametersCount { get; }
1417 TypeParameterSpec[] TypeParameters { get; }
1419 TypeSpec GetAttributeCoClass ();
1420 string GetAttributeDefaultMember ();
1421 AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa);
1422 bool IsInternalAsPublic (IAssemblyDefinition assembly);
1423 void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache);
1426 class InternalType : TypeSpec, ITypeDefinition
1428 public static readonly InternalType AnonymousMethod = new InternalType ("anonymous method");
1429 public static readonly InternalType Arglist = new InternalType ("__arglist");
1430 public static readonly InternalType MethodGroup = new InternalType ("method group");
1431 public static readonly InternalType NullLiteral = new InternalType ("null");
1432 public static readonly InternalType FakeInternalType = new InternalType ("<fake$type>");
1433 public static readonly InternalType Namespace = new InternalType ("<namespace>");
1434 public static readonly InternalType ErrorType = new InternalType ("<error>");
1435 public static readonly InternalType VarOutType = new InternalType ("var out");
1437 readonly string name;
1439 InternalType (string name)
1440 : base (MemberKind.InternalCompilerType, null, null, null, Modifiers.PUBLIC)
1443 this.definition = this;
1444 cache = MemberCache.Empty;
1446 // Make all internal types CLS-compliant, non-obsolete
1447 state = (state & ~(StateFlags.CLSCompliant_Undetected | StateFlags.Obsolete_Undetected | StateFlags.MissingDependency_Undetected)) | StateFlags.CLSCompliant;
1452 public override int Arity {
1458 IAssemblyDefinition ITypeDefinition.DeclaringAssembly {
1460 throw new NotImplementedException ();
1464 bool ITypeDefinition.IsComImport {
1470 bool IMemberDefinition.IsImported {
1476 bool ITypeDefinition.IsPartial {
1482 bool ITypeDefinition.IsTypeForwarder {
1488 bool ITypeDefinition.IsCyclicTypeForwarder {
1494 public override string Name {
1500 string ITypeDefinition.Namespace {
1506 int ITypeDefinition.TypeParametersCount {
1512 TypeParameterSpec[] ITypeDefinition.TypeParameters {
1520 public override string GetSignatureForError ()
1525 #region ITypeDefinition Members
1527 TypeSpec ITypeDefinition.GetAttributeCoClass ()
1532 string ITypeDefinition.GetAttributeDefaultMember ()
1537 AttributeUsageAttribute ITypeDefinition.GetAttributeUsage (PredefinedAttribute pa)
1542 bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly)
1544 throw new NotImplementedException ();
1547 void ITypeDefinition.LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
1549 throw new NotImplementedException ();
1552 string[] IMemberDefinition.ConditionalConditions ()
1557 ObsoleteAttribute IMemberDefinition.GetAttributeObsolete ()
1562 bool? IMemberDefinition.CLSAttributeValue {
1568 void IMemberDefinition.SetIsAssigned ()
1572 void IMemberDefinition.SetIsUsed ()
1580 // Common base class for composite types
1582 public abstract class ElementTypeSpec : TypeSpec, ITypeDefinition
1584 protected ElementTypeSpec (MemberKind kind, TypeSpec element, MetaType info)
1585 : base (kind, element.DeclaringType, null, info, element.Modifiers)
1587 this.Element = element;
1589 state &= ~SharedStateFlags;
1590 state |= (element.state & SharedStateFlags);
1592 if (element.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1593 state |= StateFlags.HasDynamicElement;
1595 // Has to use its own type definition instead of just element definition to
1596 // correctly identify itself for cases like x.MemberDefininition == predefined.MemberDefinition
1597 this.definition = this;
1599 cache = MemberCache.Empty;
1604 public TypeSpec Element { get; private set; }
1606 bool ITypeDefinition.IsComImport {
1612 bool ITypeDefinition.IsPartial {
1618 bool ITypeDefinition.IsTypeForwarder {
1624 bool ITypeDefinition.IsCyclicTypeForwarder {
1630 public override string Name {
1632 throw new NotSupportedException ();
1638 public override void CheckObsoleteness (IMemberContext mc, Location loc)
1640 Element.CheckObsoleteness (mc, loc);
1643 public override ObsoleteAttribute GetAttributeObsolete ()
1645 return Element.GetAttributeObsolete ();
1648 protected virtual string GetPostfixSignature ()
1653 public override string GetSignatureForDocumentation (bool explicitName)
1655 return Element.GetSignatureForDocumentation (explicitName) + GetPostfixSignature ();
1658 public override string GetSignatureForError ()
1660 return Element.GetSignatureForError () + GetPostfixSignature ();
1663 public override TypeSpec Mutate (TypeParameterMutator mutator)
1665 var me = Element.Mutate (mutator);
1669 var mutated = (ElementTypeSpec) MemberwiseClone ();
1670 mutated.Element = me;
1671 mutated.info = null;
1675 #region ITypeDefinition Members
1677 IAssemblyDefinition ITypeDefinition.DeclaringAssembly {
1679 return Element.MemberDefinition.DeclaringAssembly;
1683 bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly)
1685 return Element.MemberDefinition.IsInternalAsPublic (assembly);
1688 public string Namespace {
1689 get { throw new NotImplementedException (); }
1692 public int TypeParametersCount {
1698 public TypeParameterSpec[] TypeParameters {
1700 throw new NotSupportedException ();
1704 public TypeSpec GetAttributeCoClass ()
1706 return Element.MemberDefinition.GetAttributeCoClass ();
1709 public string GetAttributeDefaultMember ()
1711 return Element.MemberDefinition.GetAttributeDefaultMember ();
1714 public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
1716 Element.MemberDefinition.LoadMembers (declaringType, onlyTypes, ref cache);
1719 public bool IsImported {
1721 return Element.MemberDefinition.IsImported;
1725 public string[] ConditionalConditions ()
1727 return Element.MemberDefinition.ConditionalConditions ();
1730 bool? IMemberDefinition.CLSAttributeValue {
1732 return Element.MemberDefinition.CLSAttributeValue;
1736 public void SetIsAssigned ()
1738 Element.MemberDefinition.SetIsAssigned ();
1741 public void SetIsUsed ()
1743 Element.MemberDefinition.SetIsUsed ();
1749 public class ArrayContainer : ElementTypeSpec
1751 public struct TypeRankPair : IEquatable<TypeRankPair>
1756 public TypeRankPair (TypeSpec ts, int rank)
1762 public override int GetHashCode ()
1764 return ts.GetHashCode () ^ rank.GetHashCode ();
1767 #region IEquatable<Tuple<T1,T2>> Members
1769 public bool Equals (TypeRankPair other)
1771 return other.ts == ts && other.rank == rank;
1778 readonly ModuleContainer module;
1780 private ArrayContainer (ModuleContainer module, TypeSpec element, int rank)
1781 : base (MemberKind.ArrayType, element, null)
1783 this.module = module;
1793 public MethodInfo GetConstructor ()
1795 var mb = module.Builder;
1797 var arg_types = new MetaType[rank];
1798 for (int i = 0; i < rank; i++)
1799 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1801 var ctor = mb.GetArrayMethod (
1802 GetMetaInfo (), Constructor.ConstructorName,
1803 CallingConventions.HasThis,
1809 public MethodInfo GetAddressMethod ()
1811 var mb = module.Builder;
1813 var arg_types = new MetaType[rank];
1814 for (int i = 0; i < rank; i++)
1815 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1817 var address = mb.GetArrayMethod (
1818 GetMetaInfo (), "Address",
1819 CallingConventions.HasThis | CallingConventions.Standard,
1820 ReferenceContainer.MakeType (module, Element).GetMetaInfo (), arg_types);
1825 public MethodInfo GetGetMethod ()
1827 var mb = module.Builder;
1829 var arg_types = new MetaType[rank];
1830 for (int i = 0; i < rank; i++)
1831 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1833 var get = mb.GetArrayMethod (
1834 GetMetaInfo (), "Get",
1835 CallingConventions.HasThis | CallingConventions.Standard,
1836 Element.GetMetaInfo (), arg_types);
1841 public MethodInfo GetSetMethod ()
1843 var mb = module.Builder;
1845 var arg_types = new MetaType[rank + 1];
1846 for (int i = 0; i < rank; i++)
1847 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1849 arg_types[rank] = Element.GetMetaInfo ();
1851 var set = mb.GetArrayMethod (
1852 GetMetaInfo (), "Set",
1853 CallingConventions.HasThis | CallingConventions.Standard,
1854 module.Compiler.BuiltinTypes.Void.GetMetaInfo (), arg_types);
1859 public override MetaType GetMetaInfo ()
1863 info = Element.GetMetaInfo ().MakeArrayType ();
1865 info = Element.GetMetaInfo ().MakeArrayType (rank);
1871 protected override string GetPostfixSignature()
1873 return GetPostfixSignature (rank);
1876 public static string GetPostfixSignature (int rank)
1878 StringBuilder sb = new StringBuilder ();
1880 for (int i = 1; i < rank; i++) {
1885 return sb.ToString ();
1888 public override string GetSignatureForDocumentation (bool explicitName)
1890 StringBuilder sb = new StringBuilder ();
1891 GetElementSignatureForDocumentation (sb, explicitName);
1892 return sb.ToString ();
1895 void GetElementSignatureForDocumentation (StringBuilder sb, bool explicitName)
1897 var ac = Element as ArrayContainer;
1899 sb.Append (Element.GetSignatureForDocumentation (explicitName));
1901 ac.GetElementSignatureForDocumentation (sb, explicitName);
1904 sb.Append (GetPostfixSignature (rank));
1907 for (int i = 1; i < rank; i++) {
1917 public static ArrayContainer MakeType (ModuleContainer module, TypeSpec element)
1919 return MakeType (module, element, 1);
1922 public static ArrayContainer MakeType (ModuleContainer module, TypeSpec element, int rank)
1925 var key = new TypeRankPair (element, rank);
1926 if (!module.ArrayTypesCache.TryGetValue (key, out ac)) {
1927 ac = new ArrayContainer (module, element, rank);
1928 ac.BaseType = module.Compiler.BuiltinTypes.Array;
1929 ac.Interfaces = ac.BaseType.Interfaces;
1931 module.ArrayTypesCache.Add (key, ac);
1937 public override List<MissingTypeSpecReference> ResolveMissingDependencies (MemberSpec caller)
1939 return Element.ResolveMissingDependencies (caller);
1943 class ReferenceContainer : ElementTypeSpec
1945 private ReferenceContainer (TypeSpec element)
1946 : base (MemberKind.Class, element, null) // TODO: Kind.Class is most likely wrong
1950 public override MetaType GetMetaInfo ()
1953 info = Element.GetMetaInfo ().MakeByRefType ();
1959 public static ReferenceContainer MakeType (ModuleContainer module, TypeSpec element)
1961 ReferenceContainer pc;
1962 if (!module.ReferenceTypesCache.TryGetValue (element, out pc)) {
1963 pc = new ReferenceContainer (element);
1964 module.ReferenceTypesCache.Add (element, pc);
1971 class PointerContainer : ElementTypeSpec
1973 private PointerContainer (TypeSpec element)
1974 : base (MemberKind.PointerType, element, null)
1976 // It's never CLS-Compliant
1977 state &= ~StateFlags.CLSCompliant_Undetected;
1980 public override MetaType GetMetaInfo ()
1983 info = Element.GetMetaInfo ().MakePointerType ();
1989 protected override string GetPostfixSignature()
1994 public static PointerContainer MakeType (ModuleContainer module, TypeSpec element)
1996 PointerContainer pc;
1997 if (!module.PointerTypesCache.TryGetValue (element, out pc)) {
1998 pc = new PointerContainer (element);
1999 module.PointerTypesCache.Add (element, pc);
2006 public class MissingTypeSpecReference
2008 public MissingTypeSpecReference (TypeSpec type, MemberSpec caller)
2014 public TypeSpec Type { get; private set; }
2015 public MemberSpec Caller { get; private set; }