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);
121 public bool IsArray {
123 return Kind == MemberKind.ArrayType;
127 public bool IsAttribute {
134 if (type.BuiltinType == BuiltinTypeSpec.Type.Attribute)
140 type = type.base_type;
141 } while (type != null);
147 public bool IsInterface {
149 return Kind == MemberKind.Interface;
153 public bool IsClass {
155 return Kind == MemberKind.Class;
159 public bool IsConstantCompatible {
161 if ((Kind & (MemberKind.Enum | MemberKind.Class | MemberKind.Interface | MemberKind.Delegate | MemberKind.ArrayType)) != 0)
164 switch (BuiltinType) {
165 case BuiltinTypeSpec.Type.Int:
166 case BuiltinTypeSpec.Type.UInt:
167 case BuiltinTypeSpec.Type.Long:
168 case BuiltinTypeSpec.Type.ULong:
169 case BuiltinTypeSpec.Type.Float:
170 case BuiltinTypeSpec.Type.Double:
171 case BuiltinTypeSpec.Type.Char:
172 case BuiltinTypeSpec.Type.Short:
173 case BuiltinTypeSpec.Type.Decimal:
174 case BuiltinTypeSpec.Type.Bool:
175 case BuiltinTypeSpec.Type.SByte:
176 case BuiltinTypeSpec.Type.Byte:
177 case BuiltinTypeSpec.Type.UShort:
178 case BuiltinTypeSpec.Type.Dynamic:
186 public bool IsDelegate {
188 return Kind == MemberKind.Delegate;
193 // Returns true for instances of Expression<T>
195 public virtual bool IsExpressionTreeType {
200 state = value ? state | StateFlags.InflatedExpressionType : state & ~StateFlags.InflatedExpressionType;
206 return Kind == MemberKind.Enum;
211 // Returns true for instances of IList<T>, IEnumerable<T>, ICollection<T>
213 public virtual bool IsArrayGenericInterface {
218 state = value ? state | StateFlags.GenericIterateInterface : state & ~StateFlags.GenericIterateInterface;
223 // Returns true for instances of System.Threading.Tasks.Task<T>
225 public virtual bool IsGenericTask {
230 state = value ? state | StateFlags.GenericTask : state & ~StateFlags.GenericTask;
234 // TODO: Should probably do
235 // IsGenericType -- recursive
236 // HasTypeParameter -- non-recursive
237 public bool IsGenericOrParentIsGeneric {
243 ts = ts.declaringType;
244 } while (ts != null);
250 public bool IsGenericParameter {
252 return Kind == MemberKind.TypeParameter;
257 // Returns true for instances of Nullable<T>
259 public virtual bool IsNullableType {
264 state = value ? state | StateFlags.InflatedNullableType : state & ~StateFlags.InflatedNullableType;
268 public bool IsNested {
269 get { return declaringType != null && Kind != MemberKind.TypeParameter; }
272 public bool IsPointer {
274 return Kind == MemberKind.PointerType;
278 public bool IsSealed {
279 get { return (Modifiers & Modifiers.SEALED) != 0; }
282 public bool IsSpecialRuntimeType {
284 return (state & StateFlags.SpecialRuntimeType) != 0;
287 state = value ? state | StateFlags.SpecialRuntimeType : state & ~StateFlags.SpecialRuntimeType;
291 public bool IsStruct {
293 return Kind == MemberKind.Struct;
297 public bool IsStructOrEnum {
299 return (Kind & (MemberKind.Struct | MemberKind.Enum)) != 0;
303 public bool IsTypeBuilder {
308 var meta = GetMetaInfo().GetType ();
309 return meta == TypeBuilder || meta == GenericTypeBuilder;
315 // Whether a type is unmanaged. This is used by the unsafe code
317 public bool IsUnmanaged {
320 return ((ElementTypeSpec) this).Element.IsUnmanaged;
322 var ds = MemberDefinition as TypeDefinition;
324 return ds.IsUnmanagedType ();
326 if (Kind == MemberKind.Void)
329 if (Kind == MemberKind.TypeParameter)
332 if (IsNested && DeclaringType.IsGenericOrParentIsGeneric)
335 return IsValueType (this);
340 // A cache of all type members (including nested types)
342 public MemberCache MemberCache {
344 if (cache == null || (state & StateFlags.PendingMemberCacheMembers) != 0)
345 InitializeMemberCache (false);
351 throw new InternalErrorException ("Membercache reset");
357 public MemberCache MemberCacheTypes {
360 InitializeMemberCache (true);
366 public new ITypeDefinition MemberDefinition {
368 return (ITypeDefinition) definition;
372 // TODO: Wouldn't be better to rely on cast to InflatedTypeSpec and
373 // remove the property, YES IT WOULD !!!
374 public virtual TypeSpec[] TypeArguments {
375 get { return TypeSpec.EmptyTypes; }
380 public virtual bool AddInterface (TypeSpec iface)
382 if ((state & StateFlags.InterfacesExpanded) != 0)
383 throw new InternalErrorException ("Modifying expanded interface list");
385 if (ifaces == null) {
386 ifaces = new List<TypeSpec> { iface };
390 if (!ifaces.Contains (iface)) {
399 // Special version used during type definition
401 public bool AddInterfaceDefined (TypeSpec iface)
403 if (!AddInterface (iface))
407 // We can get into a situation where a type is inflated before
408 // its interfaces are resoved. Consider this situation
410 // class A<T> : X<A<int>>, IFoo {}
412 // When resolving base class of X`1 we inflate context type A`1
413 // All this happens before we even hit IFoo resolve. Without
414 // additional expansion any inside usage of A<T> would miss IFoo
415 // interface because it comes from early inflated A`1 definition.
417 if (inflated_instances != null) {
419 // Inflate only existing instances not any new instances added
420 // during AddInterface
422 var inflated_existing = inflated_instances.Values.ToArray ();
423 foreach (var inflated in inflated_existing) {
424 inflated.AddInterface (iface);
432 // Returns all type arguments, usefull for nested types
434 public static TypeSpec[] GetAllTypeArguments (TypeSpec type)
436 IList<TypeSpec> targs = TypeSpec.EmptyTypes;
439 if (type.Arity > 0) {
440 if (targs.Count == 0) {
441 targs = type.TypeArguments;
443 var list = targs as List<TypeSpec> ?? new List<TypeSpec> (targs);
444 list.AddRange (type.TypeArguments);
449 type = type.declaringType;
450 } while (type != null);
452 return targs as TypeSpec[] ?? ((List<TypeSpec>) targs).ToArray ();
455 public AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa)
457 if (Kind != MemberKind.Class)
458 throw new InternalErrorException ();
461 return Attribute.DefaultUsageAttribute;
463 AttributeUsageAttribute aua = null;
465 while (type != null) {
466 aua = type.MemberDefinition.GetAttributeUsage (pa);
470 type = type.BaseType;
477 // Return metadata information used during emit to describe the type
479 public virtual MetaType GetMetaInfo ()
484 public virtual TypeSpec GetDefinition ()
490 // Text representation of type used by documentation writer
492 public sealed override string GetSignatureForDocumentation ()
494 return GetSignatureForDocumentation (false);
497 public virtual string GetSignatureForDocumentation (bool explicitName)
499 StringBuilder sb = new StringBuilder ();
501 sb.Append (DeclaringType.GetSignatureForDocumentation (explicitName));
502 } else if (MemberDefinition.Namespace != null) {
503 sb.Append (explicitName ? MemberDefinition.Namespace.Replace ('.', '#') : MemberDefinition.Namespace);
507 sb.Append (explicitName ? "#" : ".");
511 if (this is InflatedTypeSpec) {
513 for (int i = 0; i < Arity; ++i) {
517 sb.Append (TypeArguments[i].GetSignatureForDocumentation (explicitName));
522 sb.Append (Arity.ToString ());
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 var imported = MemberDefinition.DeclaringAssembly as ImportedAssemblyDefinition;
551 var location = imported != null ?
552 System.IO.Path.GetFullPath (imported.Location) :
553 ((MemberCore)MemberDefinition).Location.NameFullPath;
555 return string.Format ("{0} [{1} -- {2}]", GetSignatureForError (),
556 MemberDefinition.DeclaringAssembly.FullName,
560 protected virtual string GetTypeNameSignature ()
565 return "<" + TypeManager.CSharpName (MemberDefinition.TypeParameters) + ">";
568 public bool ImplementsInterface (TypeSpec iface, bool variantly)
570 var ifaces = Interfaces;
571 if (ifaces != null) {
572 for (int i = 0; i < ifaces.Count; ++i) {
573 if (TypeSpecComparer.IsEqual (ifaces[i], iface))
576 if (variantly && TypeSpecComparer.Variant.IsEqual (ifaces[i], iface))
584 protected virtual void InitializeMemberCache (bool onlyTypes)
587 MemberDefinition.LoadMembers (this, onlyTypes, ref cache);
588 } catch (Exception e) {
589 throw new InternalErrorException (e, "Unexpected error when loading type `{0}'", GetSignatureForError ());
593 state |= StateFlags.PendingMemberCacheMembers;
595 state &= ~StateFlags.PendingMemberCacheMembers;
599 // Is @baseClass base implementation of @type. With enabled @dynamicIsEqual the slower
600 // comparison is used to hide differences between `object' and `dynamic' for generic
601 // types. Should not be used for comparisons where G<object> != G<dynamic>
603 public static bool IsBaseClass (TypeSpec type, TypeSpec baseClass, bool dynamicIsObject)
605 if (dynamicIsObject && baseClass.IsGeneric) {
607 // Returns true for a hierarchies like this when passing baseClass of A<dynamic>
609 // class B : A<object> {}
611 type = type.BaseType;
612 while (type != null) {
613 if (TypeSpecComparer.IsEqual (type, baseClass))
616 type = type.BaseType;
622 while (type != null) {
623 type = type.BaseType;
624 if (type == baseClass)
631 public static bool IsReferenceType (TypeSpec t)
634 case MemberKind.TypeParameter:
635 return ((TypeParameterSpec) t).IsReferenceType;
636 case MemberKind.Struct:
637 case MemberKind.Enum:
638 case MemberKind.Void:
639 case MemberKind.PointerType:
641 case MemberKind.InternalCompilerType:
643 // Null is considered to be a reference type
645 return t == InternalType.NullLiteral || t.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
651 public static bool IsNonNullableValueType (TypeSpec t)
654 case MemberKind.TypeParameter:
655 return ((TypeParameterSpec) t).IsValueType;
656 case MemberKind.Struct:
657 return !t.IsNullableType;
658 case MemberKind.Enum:
665 public static bool IsValueType (TypeSpec t)
668 case MemberKind.TypeParameter:
669 return ((TypeParameterSpec) t).IsValueType;
670 case MemberKind.Struct:
671 case MemberKind.Enum:
678 public override MemberSpec InflateMember (TypeParameterInflator inflator)
680 var targs = IsGeneric ? MemberDefinition.TypeParameters : TypeSpec.EmptyTypes;
683 // When inflating nested type from inside the type instance will be same
684 // because type parameters are same for all nested types
686 if (DeclaringType == inflator.TypeInstance) {
687 return MakeGenericType (inflator.Context, targs);
690 return new InflatedTypeSpec (inflator.Context, this, inflator.TypeInstance, targs);
694 // Inflates current type using specific type arguments
696 public InflatedTypeSpec MakeGenericType (IModuleContext context, TypeSpec[] targs)
698 if (targs.Length == 0 && !IsNested)
699 throw new ArgumentException ("Empty type arguments for type " + GetSignatureForError ());
701 InflatedTypeSpec instance;
703 if (inflated_instances == null) {
704 inflated_instances = new Dictionary<TypeSpec[], InflatedTypeSpec> (TypeSpecComparer.Default);
707 instance = this as InflatedTypeSpec;
708 if (instance != null) {
710 // Nested types could be inflated on already inflated instances
711 // Caching this type ensured we are using same instance for
712 // inside/outside inflation using local type parameters
714 inflated_instances.Add (TypeArguments, instance);
719 if (!inflated_instances.TryGetValue (targs, out instance)) {
720 if (GetDefinition () != this && !IsNested)
721 throw new InternalErrorException ("`{0}' must be type definition or nested non-inflated type to MakeGenericType",
722 GetSignatureForError ());
724 instance = new InflatedTypeSpec (context, this, declaringType, targs);
725 inflated_instances.Add (targs, instance);
731 public virtual TypeSpec Mutate (TypeParameterMutator mutator)
736 public override List<MissingTypeSpecReference> ResolveMissingDependencies (MemberSpec caller)
738 List<MissingTypeSpecReference> missing = null;
740 if (Kind == MemberKind.MissingType) {
741 missing = new List<MissingTypeSpecReference> ();
742 missing.Add (new MissingTypeSpecReference (this, caller));
746 foreach (var targ in TypeArguments) {
747 if (targ.Kind == MemberKind.MissingType) {
749 missing = new List<MissingTypeSpecReference> ();
751 missing.Add (new MissingTypeSpecReference (targ, caller));
755 if (Interfaces != null) {
756 foreach (var iface in Interfaces) {
757 if (iface.Kind == MemberKind.MissingType) {
759 missing = new List<MissingTypeSpecReference> ();
761 missing.Add (new MissingTypeSpecReference (iface, caller));
766 if (MemberDefinition.TypeParametersCount > 0) {
767 foreach (var tp in MemberDefinition.TypeParameters) {
768 var tp_missing = tp.GetMissingDependencies (this);
769 if (tp_missing != null) {
771 missing = new List<MissingTypeSpecReference> ();
773 missing.AddRange (tp_missing);
778 if (missing != null || BaseType == null)
781 return BaseType.ResolveMissingDependencies (this);
784 public void SetMetaInfo (MetaType info)
786 if (this.info != null)
787 throw new InternalErrorException ("MetaInfo reset");
792 public void SetExtensionMethodContainer ()
794 modifiers |= Modifiers.METHOD_EXTENSION;
797 public void UpdateInflatedInstancesBaseType ()
800 // When nested class has a partial part the situation where parent type
801 // is inflated before its base type is defined can occur. In such case
802 // all inflated (should be only 1) instansted need to be updated
804 // partial class A<T> {
805 // partial class B : A<int> { }
808 // partial class A<T> : X {}
810 if (inflated_instances == null)
813 foreach (var inflated in inflated_instances) {
815 // Don't need to inflate possible generic type because for now the method
816 // is always used from within the nested type
818 inflated.Value.BaseType = base_type;
824 // Special version used for types which must exist in corlib or
825 // the compiler cannot work
827 public sealed class BuiltinTypeSpec : TypeSpec
833 // Ordered carefully for fast compares
861 MulticastDelegate = 23,
874 readonly string name;
876 public BuiltinTypeSpec (MemberKind kind, string ns, string name, Type builtinKind)
877 : base (kind, null, null, null, Modifiers.PUBLIC)
879 this.type = builtinKind;
884 public BuiltinTypeSpec (string name, Type builtinKind)
885 : this (MemberKind.InternalCompilerType, "", name, builtinKind)
887 // Make all internal types CLS-compliant, non-obsolete, compact
888 state = (state & ~(StateFlags.CLSCompliant_Undetected | StateFlags.Obsolete_Undetected | StateFlags.MissingDependency_Undetected)) | StateFlags.CLSCompliant;
893 public override int Arity {
899 public override BuiltinTypeSpec.Type BuiltinType {
905 public string FullName {
907 return ns + '.' + name;
911 public override string Name {
917 public string Namespace {
925 public static bool IsPrimitiveType (TypeSpec type)
927 return type.BuiltinType >= Type.FirstPrimitive && type.BuiltinType <= Type.LastPrimitive;
930 public static bool IsPrimitiveTypeOrDecimal (TypeSpec type)
932 return type.BuiltinType >= Type.FirstPrimitive && type.BuiltinType <= Type.Decimal;
935 public override string GetSignatureForError ()
938 case "Int32": return "int";
939 case "Int64": return "long";
940 case "String": return "string";
941 case "Boolean": return "bool";
942 case "Void": return "void";
943 case "Object": return "object";
944 case "UInt32": return "uint";
945 case "Int16": return "short";
946 case "UInt16": return "ushort";
947 case "UInt64": return "ulong";
948 case "Single": return "float";
949 case "Double": return "double";
950 case "Decimal": return "decimal";
951 case "Char": return "char";
952 case "Byte": return "byte";
953 case "SByte": return "sbyte";
963 // Returns the size of type if known, otherwise, 0
965 public static int GetSize (TypeSpec type)
967 switch (type.BuiltinType) {
991 public void SetDefinition (ITypeDefinition td, MetaType type, Modifiers mod)
993 this.definition = td;
995 this.modifiers |= (mod & ~Modifiers.AccessibilityMask);
998 public void SetDefinition (TypeSpec ts)
1000 this.definition = ts.MemberDefinition;
1001 this.info = ts.GetMetaInfo ();
1002 this.BaseType = ts.BaseType;
1003 this.Interfaces = ts.Interfaces;
1004 this.modifiers = ts.Modifiers;
1009 // Various type comparers used by compiler
1011 static class TypeSpecComparer
1014 // Does strict reference comparion only
1016 public static readonly DefaultImpl Default = new DefaultImpl ();
1018 public class DefaultImpl : IEqualityComparer<TypeSpec[]>
1020 #region IEqualityComparer<TypeSpec[]> Members
1022 bool IEqualityComparer<TypeSpec[]>.Equals (TypeSpec[] x, TypeSpec[] y)
1027 if (x.Length != y.Length)
1030 for (int i = 0; i < x.Length; ++i)
1037 int IEqualityComparer<TypeSpec[]>.GetHashCode (TypeSpec[] obj)
1040 for (int i = 0; i < obj.Length; ++i)
1041 hash = (hash << 5) - hash + obj[i].GetHashCode ();
1050 // When comparing type signature of overrides or overloads
1051 // this version tolerates different MVARs at same position
1053 public static class Override
1055 public static bool IsEqual (TypeSpec a, TypeSpec b)
1061 // Consider the following example:
1063 // public abstract class A
1065 // public abstract T Foo<T>();
1068 // public class B : A
1070 // public override U Foo<T>() { return default (U); }
1073 // Here, `T' and `U' are method type parameters from different methods
1074 // (A.Foo and B.Foo), so both `==' and Equals() will fail.
1076 // However, since we're determining whether B.Foo() overrides A.Foo(),
1077 // we need to do a signature based comparision and consider them equal.
1080 var tp_a = a as TypeParameterSpec;
1082 var tp_b = b as TypeParameterSpec;
1083 return tp_b != null && tp_a.IsMethodOwned == tp_b.IsMethodOwned && tp_a.DeclaredPosition == tp_b.DeclaredPosition;
1086 var ac_a = a as ArrayContainer;
1088 var ac_b = b as ArrayContainer;
1089 return ac_b != null && ac_a.Rank == ac_b.Rank && IsEqual (ac_a.Element, ac_b.Element);
1092 if (a.BuiltinType == BuiltinTypeSpec.Type.Dynamic || b.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1093 return b.BuiltinType == BuiltinTypeSpec.Type.Object || a.BuiltinType == BuiltinTypeSpec.Type.Object;
1095 if (a.MemberDefinition != b.MemberDefinition)
1099 for (int i = 0; i < a.TypeArguments.Length; ++i) {
1100 if (!IsEqual (a.TypeArguments[i], b.TypeArguments[i]))
1104 a = a.DeclaringType;
1105 b = b.DeclaringType;
1106 } while (a != null);
1111 public static bool IsEqual (TypeSpec[] a, TypeSpec[] b)
1116 if (a.Length != b.Length)
1119 for (int i = 0; i < a.Length; ++i) {
1120 if (!IsEqual (a[i], b[i]))
1129 // Compares unordered arrays
1131 public static bool IsSame (TypeSpec[] a, TypeSpec[] b)
1136 if (a == null || b == null || a.Length != b.Length)
1139 for (int ai = 0; ai < a.Length; ++ai) {
1141 for (int bi = 0; bi < b.Length; ++bi) {
1142 if (IsEqual (a[ai], b[bi])) {
1155 public static bool IsEqual (AParametersCollection a, AParametersCollection b)
1160 if (a.Count != b.Count)
1163 for (int i = 0; i < a.Count; ++i) {
1164 if (!IsEqual (a.Types[i], b.Types[i]))
1167 if ((a.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (b.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
1176 // Type variance equality comparison
1178 public static class Variant
1180 public static bool IsEqual (TypeSpec type1, TypeSpec type2)
1182 if (!type1.IsGeneric || !type2.IsGeneric)
1185 var target_type_def = type2.MemberDefinition;
1186 if (type1.MemberDefinition != target_type_def)
1189 var t1_targs = type1.TypeArguments;
1190 var t2_targs = type2.TypeArguments;
1191 var targs_definition = target_type_def.TypeParameters;
1193 if (!type1.IsInterface && !type1.IsDelegate) {
1197 for (int i = 0; i < targs_definition.Length; ++i) {
1198 if (TypeSpecComparer.IsEqual (t1_targs[i], t2_targs[i]))
1201 Variance v = targs_definition[i].Variance;
1202 if (v == Variance.None) {
1206 if (v == Variance.Covariant) {
1207 if (!Convert.ImplicitReferenceConversionExists (t1_targs[i], t2_targs[i]))
1209 } else if (!Convert.ImplicitReferenceConversionExists (t2_targs[i], t1_targs[i])) {
1219 // Checks whether two generic instances may become equal for some
1220 // particular instantiation (26.3.1).
1222 public static class Unify
1225 // Either @a or @b must be generic type
1227 public static bool IsEqual (TypeSpec a, TypeSpec b)
1229 if (a.MemberDefinition != b.MemberDefinition) {
1230 var base_ifaces = a.Interfaces;
1231 if (base_ifaces != null) {
1232 foreach (var base_iface in base_ifaces) {
1233 if (base_iface.Arity > 0 && IsEqual (base_iface, b))
1241 var ta = a.TypeArguments;
1242 var tb = b.TypeArguments;
1243 for (int i = 0; i < ta.Length; i++) {
1244 if (!MayBecomeEqualGenericTypes (ta[i], tb[i]))
1248 if (a.IsNested && b.IsNested)
1249 return IsEqual (a.DeclaringType, b.DeclaringType);
1254 static bool ContainsTypeParameter (TypeSpec tparam, TypeSpec type)
1256 TypeSpec[] targs = type.TypeArguments;
1257 for (int i = 0; i < targs.Length; i++) {
1258 if (tparam == targs[i])
1261 if (ContainsTypeParameter (tparam, targs[i]))
1269 /// Check whether `a' and `b' may become equal generic types.
1270 /// The algorithm to do that is a little bit complicated.
1272 static bool MayBecomeEqualGenericTypes (TypeSpec a, TypeSpec b)
1274 if (a.IsGenericParameter) {
1276 // If a is an array of a's type, they may never
1283 // If b is a generic parameter or an actual type,
1284 // they may become equal:
1286 // class X<T,U> : I<T>, I<U>
1287 // class X<T> : I<T>, I<float>
1289 if (b.IsGenericParameter)
1290 return a != b && a.DeclaringType == b.DeclaringType;
1293 // We're now comparing a type parameter with a
1294 // generic instance. They may become equal unless
1295 // the type parameter appears anywhere in the
1296 // generic instance:
1298 // class X<T,U> : I<T>, I<X<U>>
1299 // -> error because you could instanciate it as
1302 // class X<T> : I<T>, I<X<T>> -> ok
1305 return !ContainsTypeParameter (a, b);
1308 if (b.IsGenericParameter)
1309 return MayBecomeEqualGenericTypes (b, a);
1312 // At this point, neither a nor b are a type parameter.
1314 // If one of them is a generic instance, compare them (if the
1315 // other one is not a generic instance, they can never
1318 if (TypeManager.IsGenericType (a) || TypeManager.IsGenericType (b))
1319 return IsEqual (a, b);
1322 // If both of them are arrays.
1324 var a_ac = a as ArrayContainer;
1326 var b_ac = b as ArrayContainer;
1327 if (b_ac == null || a_ac.Rank != b_ac.Rank)
1330 return MayBecomeEqualGenericTypes (a_ac.Element, b_ac.Element);
1334 // Ok, two ordinary types.
1340 public static bool Equals (TypeSpec[] x, TypeSpec[] y)
1345 if (x.Length != y.Length)
1348 for (int i = 0; i < x.Length; ++i)
1349 if (!IsEqual (x[i], y[i]))
1356 // Identity type conversion
1358 // Default reference comparison, it has to be used when comparing
1359 // two possible dynamic/internal types
1361 public static bool IsEqual (TypeSpec a, TypeSpec b)
1364 // This also rejects dynamic == dynamic
1365 return a.Kind != MemberKind.InternalCompilerType || a.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
1368 if (a == null || b == null)
1372 var a_a = (ArrayContainer) a;
1373 var b_a = b as ArrayContainer;
1377 return a_a.Rank == b_a.Rank && IsEqual (a_a.Element, b_a.Element);
1380 if (!a.IsGeneric || !b.IsGeneric) {
1382 // object and dynamic are considered equivalent there is an identity conversion
1383 // between object and dynamic, and between constructed types that are the same
1384 // when replacing all occurences of dynamic with object.
1386 if (a.BuiltinType == BuiltinTypeSpec.Type.Dynamic || b.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1387 return b.BuiltinType == BuiltinTypeSpec.Type.Object || a.BuiltinType == BuiltinTypeSpec.Type.Object;
1392 if (a.MemberDefinition != b.MemberDefinition)
1396 if (!Equals (a.TypeArguments, b.TypeArguments))
1399 a = a.DeclaringType;
1400 b = b.DeclaringType;
1401 } while (a != null);
1407 public interface ITypeDefinition : IMemberDefinition
1409 IAssemblyDefinition DeclaringAssembly { get; }
1410 string Namespace { get; }
1411 bool IsPartial { get; }
1412 bool IsComImport { get; }
1413 bool IsTypeForwarder { get; }
1414 bool IsCyclicTypeForwarder { get; }
1415 int TypeParametersCount { get; }
1416 TypeParameterSpec[] TypeParameters { get; }
1418 TypeSpec GetAttributeCoClass ();
1419 string GetAttributeDefaultMember ();
1420 AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa);
1421 bool IsInternalAsPublic (IAssemblyDefinition assembly);
1422 void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache);
1425 class InternalType : TypeSpec, ITypeDefinition
1427 public static readonly InternalType AnonymousMethod = new InternalType ("anonymous method");
1428 public static readonly InternalType Arglist = new InternalType ("__arglist");
1429 public static readonly InternalType MethodGroup = new InternalType ("method group");
1430 public static readonly InternalType NullLiteral = new InternalType ("null");
1431 public static readonly InternalType FakeInternalType = new InternalType ("<fake$type>");
1432 public static readonly InternalType Namespace = new InternalType ("<namespace>");
1433 public static readonly InternalType ErrorType = new InternalType ("<error>");
1434 public static readonly InternalType VarOutType = new InternalType ("var out");
1436 readonly string name;
1438 InternalType (string name)
1439 : base (MemberKind.InternalCompilerType, null, null, null, Modifiers.PUBLIC)
1442 this.definition = this;
1443 cache = MemberCache.Empty;
1445 // Make all internal types CLS-compliant, non-obsolete
1446 state = (state & ~(StateFlags.CLSCompliant_Undetected | StateFlags.Obsolete_Undetected | StateFlags.MissingDependency_Undetected)) | StateFlags.CLSCompliant;
1451 public override int Arity {
1457 IAssemblyDefinition ITypeDefinition.DeclaringAssembly {
1459 throw new NotImplementedException ();
1463 bool ITypeDefinition.IsComImport {
1469 bool IMemberDefinition.IsImported {
1475 bool ITypeDefinition.IsPartial {
1481 bool ITypeDefinition.IsTypeForwarder {
1487 bool ITypeDefinition.IsCyclicTypeForwarder {
1493 public override string Name {
1499 string ITypeDefinition.Namespace {
1505 int ITypeDefinition.TypeParametersCount {
1511 TypeParameterSpec[] ITypeDefinition.TypeParameters {
1519 public override string GetSignatureForError ()
1524 #region ITypeDefinition Members
1526 TypeSpec ITypeDefinition.GetAttributeCoClass ()
1531 string ITypeDefinition.GetAttributeDefaultMember ()
1536 AttributeUsageAttribute ITypeDefinition.GetAttributeUsage (PredefinedAttribute pa)
1541 bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly)
1543 throw new NotImplementedException ();
1546 void ITypeDefinition.LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
1548 throw new NotImplementedException ();
1551 string[] IMemberDefinition.ConditionalConditions ()
1556 ObsoleteAttribute IMemberDefinition.GetAttributeObsolete ()
1561 bool? IMemberDefinition.CLSAttributeValue {
1567 void IMemberDefinition.SetIsAssigned ()
1571 void IMemberDefinition.SetIsUsed ()
1579 // Common base class for composite types
1581 public abstract class ElementTypeSpec : TypeSpec, ITypeDefinition
1583 protected ElementTypeSpec (MemberKind kind, TypeSpec element, MetaType info)
1584 : base (kind, element.DeclaringType, null, info, element.Modifiers)
1586 this.Element = element;
1588 state &= ~SharedStateFlags;
1589 state |= (element.state & SharedStateFlags);
1591 if (element.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1592 state |= StateFlags.HasDynamicElement;
1594 // Has to use its own type definition instead of just element definition to
1595 // correctly identify itself for cases like x.MemberDefininition == predefined.MemberDefinition
1596 this.definition = this;
1598 cache = MemberCache.Empty;
1603 public TypeSpec Element { get; private set; }
1605 public override IList<TypeSpec> Interfaces {
1607 throw new NotSupportedException ();
1611 bool ITypeDefinition.IsComImport {
1617 bool ITypeDefinition.IsPartial {
1623 bool ITypeDefinition.IsTypeForwarder {
1629 bool ITypeDefinition.IsCyclicTypeForwarder {
1635 public override string Name {
1637 throw new NotSupportedException ();
1643 public override void CheckObsoleteness (IMemberContext mc, Location loc)
1645 Element.CheckObsoleteness (mc, loc);
1648 public override ObsoleteAttribute GetAttributeObsolete ()
1650 return Element.GetAttributeObsolete ();
1653 protected virtual string GetPostfixSignature ()
1658 public override string GetSignatureForDocumentation (bool explicitName)
1660 return Element.GetSignatureForDocumentation (explicitName) + GetPostfixSignature ();
1663 public override string GetSignatureForError ()
1665 return Element.GetSignatureForError () + GetPostfixSignature ();
1668 public override TypeSpec Mutate (TypeParameterMutator mutator)
1670 var me = Element.Mutate (mutator);
1674 var mutated = (ElementTypeSpec) MemberwiseClone ();
1675 mutated.Element = me;
1676 mutated.info = null;
1680 #region ITypeDefinition Members
1682 IAssemblyDefinition ITypeDefinition.DeclaringAssembly {
1684 return Element.MemberDefinition.DeclaringAssembly;
1688 bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly)
1690 return Element.MemberDefinition.IsInternalAsPublic (assembly);
1693 public string Namespace {
1694 get { throw new NotImplementedException (); }
1697 public int TypeParametersCount {
1703 public TypeParameterSpec[] TypeParameters {
1705 throw new NotSupportedException ();
1709 public TypeSpec GetAttributeCoClass ()
1711 return Element.MemberDefinition.GetAttributeCoClass ();
1714 public string GetAttributeDefaultMember ()
1716 return Element.MemberDefinition.GetAttributeDefaultMember ();
1719 public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
1721 Element.MemberDefinition.LoadMembers (declaringType, onlyTypes, ref cache);
1724 public bool IsImported {
1726 return Element.MemberDefinition.IsImported;
1730 public string[] ConditionalConditions ()
1732 return Element.MemberDefinition.ConditionalConditions ();
1735 bool? IMemberDefinition.CLSAttributeValue {
1737 return Element.MemberDefinition.CLSAttributeValue;
1741 public void SetIsAssigned ()
1743 Element.MemberDefinition.SetIsAssigned ();
1746 public void SetIsUsed ()
1748 Element.MemberDefinition.SetIsUsed ();
1754 public class ArrayContainer : ElementTypeSpec
1756 public struct TypeRankPair : IEquatable<TypeRankPair>
1761 public TypeRankPair (TypeSpec ts, int rank)
1767 public override int GetHashCode ()
1769 return ts.GetHashCode () ^ rank.GetHashCode ();
1772 #region IEquatable<Tuple<T1,T2>> Members
1774 public bool Equals (TypeRankPair other)
1776 return other.ts == ts && other.rank == rank;
1783 readonly ModuleContainer module;
1785 ArrayContainer (ModuleContainer module, TypeSpec element, int rank)
1786 : base (MemberKind.ArrayType, element, null)
1788 this.module = module;
1792 public override IList<TypeSpec> Interfaces {
1794 return BaseType.Interfaces;
1804 public MethodInfo GetConstructor ()
1806 var mb = module.Builder;
1808 var arg_types = new MetaType[rank];
1809 for (int i = 0; i < rank; i++)
1810 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1812 var ctor = mb.GetArrayMethod (
1813 GetMetaInfo (), Constructor.ConstructorName,
1814 CallingConventions.HasThis,
1820 public MethodInfo GetAddressMethod ()
1822 var mb = module.Builder;
1824 var arg_types = new MetaType[rank];
1825 for (int i = 0; i < rank; i++)
1826 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1828 var address = mb.GetArrayMethod (
1829 GetMetaInfo (), "Address",
1830 CallingConventions.HasThis | CallingConventions.Standard,
1831 ReferenceContainer.MakeType (module, Element).GetMetaInfo (), arg_types);
1836 public MethodInfo GetGetMethod ()
1838 var mb = module.Builder;
1840 var arg_types = new MetaType[rank];
1841 for (int i = 0; i < rank; i++)
1842 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1844 var get = mb.GetArrayMethod (
1845 GetMetaInfo (), "Get",
1846 CallingConventions.HasThis | CallingConventions.Standard,
1847 Element.GetMetaInfo (), arg_types);
1852 public MethodInfo GetSetMethod ()
1854 var mb = module.Builder;
1856 var arg_types = new MetaType[rank + 1];
1857 for (int i = 0; i < rank; i++)
1858 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1860 arg_types[rank] = Element.GetMetaInfo ();
1862 var set = mb.GetArrayMethod (
1863 GetMetaInfo (), "Set",
1864 CallingConventions.HasThis | CallingConventions.Standard,
1865 module.Compiler.BuiltinTypes.Void.GetMetaInfo (), arg_types);
1870 public override MetaType GetMetaInfo ()
1874 info = Element.GetMetaInfo ().MakeArrayType ();
1876 info = Element.GetMetaInfo ().MakeArrayType (rank);
1882 protected override string GetPostfixSignature()
1884 return GetPostfixSignature (rank);
1887 public static string GetPostfixSignature (int rank)
1889 StringBuilder sb = new StringBuilder ();
1891 for (int i = 1; i < rank; i++) {
1896 return sb.ToString ();
1899 public override string GetSignatureForDocumentation (bool explicitName)
1901 StringBuilder sb = new StringBuilder ();
1902 GetElementSignatureForDocumentation (sb, explicitName);
1903 return sb.ToString ();
1906 void GetElementSignatureForDocumentation (StringBuilder sb, bool explicitName)
1908 var ac = Element as ArrayContainer;
1910 sb.Append (Element.GetSignatureForDocumentation (explicitName));
1912 ac.GetElementSignatureForDocumentation (sb, explicitName);
1915 sb.Append (GetPostfixSignature (rank));
1918 for (int i = 1; i < rank; i++) {
1928 public static ArrayContainer MakeType (ModuleContainer module, TypeSpec element)
1930 return MakeType (module, element, 1);
1933 public static ArrayContainer MakeType (ModuleContainer module, TypeSpec element, int rank)
1936 var key = new TypeRankPair (element, rank);
1937 if (!module.ArrayTypesCache.TryGetValue (key, out ac)) {
1938 ac = new ArrayContainer (module, element, rank);
1939 ac.BaseType = module.Compiler.BuiltinTypes.Array;
1941 module.ArrayTypesCache.Add (key, ac);
1947 public override List<MissingTypeSpecReference> ResolveMissingDependencies (MemberSpec caller)
1949 return Element.ResolveMissingDependencies (caller);
1953 class ReferenceContainer : ElementTypeSpec
1955 ReferenceContainer (TypeSpec element)
1956 : base (MemberKind.Class, element, null) // TODO: Kind.Class is most likely wrong
1960 public override IList<TypeSpec> Interfaces {
1966 public override MetaType GetMetaInfo ()
1969 info = Element.GetMetaInfo ().MakeByRefType ();
1975 public static ReferenceContainer MakeType (ModuleContainer module, TypeSpec element)
1977 ReferenceContainer pc;
1978 if (!module.ReferenceTypesCache.TryGetValue (element, out pc)) {
1979 pc = new ReferenceContainer (element);
1980 module.ReferenceTypesCache.Add (element, pc);
1987 class PointerContainer : ElementTypeSpec
1989 private PointerContainer (TypeSpec element)
1990 : base (MemberKind.PointerType, element, null)
1992 // It's never CLS-Compliant
1993 state &= ~StateFlags.CLSCompliant_Undetected;
1996 public override IList<TypeSpec> Interfaces {
2002 public override MetaType GetMetaInfo ()
2005 info = Element.GetMetaInfo ().MakePointerType ();
2011 protected override string GetPostfixSignature()
2016 public static PointerContainer MakeType (ModuleContainer module, TypeSpec element)
2018 PointerContainer pc;
2019 if (!module.PointerTypesCache.TryGetValue (element, out pc)) {
2020 pc = new PointerContainer (element);
2021 module.PointerTypesCache.Add (element, pc);
2028 public class MissingTypeSpecReference
2030 public MissingTypeSpecReference (TypeSpec type, MemberSpec caller)
2036 public TypeSpec Type { get; private set; }
2037 public MemberSpec Caller { get; private set; }