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;
95 public bool HasNamedTupleElement {
97 return (state & StateFlags.HasNamedTupleElement) != 0;
102 // Returns a list of all interfaces including
103 // interfaces from base type or base interfaces
105 public virtual IList<TypeSpec> Interfaces {
107 if ((state & StateFlags.InterfacesImported) == 0) {
108 state |= StateFlags.InterfacesImported;
111 // Delay interfaces expansion to save memory and once all
112 // base types has been imported to avoid problems where
113 // interface references type before its base was imported
115 var imported = MemberDefinition as ImportedTypeDefinition;
116 if (imported != null && Kind != MemberKind.MissingType)
117 imported.DefineInterfaces (this);
127 public bool IsArray {
129 return Kind == MemberKind.ArrayType;
133 public bool IsAttribute {
140 if (type.BuiltinType == BuiltinTypeSpec.Type.Attribute)
146 type = type.base_type;
147 } while (type != null);
153 public bool IsInterface {
155 return Kind == MemberKind.Interface;
159 public bool IsClass {
161 return Kind == MemberKind.Class;
165 public bool IsConstantCompatible {
167 if ((Kind & (MemberKind.Enum | MemberKind.Class | MemberKind.Interface | MemberKind.Delegate | MemberKind.ArrayType)) != 0)
170 switch (BuiltinType) {
171 case BuiltinTypeSpec.Type.Int:
172 case BuiltinTypeSpec.Type.UInt:
173 case BuiltinTypeSpec.Type.Long:
174 case BuiltinTypeSpec.Type.ULong:
175 case BuiltinTypeSpec.Type.Float:
176 case BuiltinTypeSpec.Type.Double:
177 case BuiltinTypeSpec.Type.Char:
178 case BuiltinTypeSpec.Type.Short:
179 case BuiltinTypeSpec.Type.Decimal:
180 case BuiltinTypeSpec.Type.Bool:
181 case BuiltinTypeSpec.Type.SByte:
182 case BuiltinTypeSpec.Type.Byte:
183 case BuiltinTypeSpec.Type.UShort:
184 case BuiltinTypeSpec.Type.Dynamic:
192 public bool IsDelegate {
194 return Kind == MemberKind.Delegate;
199 // Returns true for instances of Expression<T>
201 public virtual bool IsExpressionTreeType {
206 state = value ? state | StateFlags.InflatedExpressionType : state & ~StateFlags.InflatedExpressionType;
212 return Kind == MemberKind.Enum;
217 // Returns true for instances of IList<T>, IEnumerable<T>, ICollection<T>
219 public virtual bool IsArrayGenericInterface {
224 state = value ? state | StateFlags.GenericIterateInterface : state & ~StateFlags.GenericIterateInterface;
229 // Returns true for instances of System.Threading.Tasks.Task<T>
231 public virtual bool IsGenericTask {
236 state = value ? state | StateFlags.GenericTask : state & ~StateFlags.GenericTask;
240 public bool IsReadOnly => (modifiers & Modifiers.READONLY) != 0;
243 // Returns true for instances of any System.ValueTuple<......> type
245 public virtual bool IsTupleType {
247 return (state & StateFlags.Tuple) != 0;
250 state = value ? state | StateFlags.Tuple : state & ~StateFlags.Tuple;
254 // TODO: Should probably do
255 // IsGenericType -- recursive
256 // HasTypeParameter -- non-recursive
257 public bool IsGenericOrParentIsGeneric {
263 ts = ts.declaringType;
264 } while (ts != null);
270 public bool IsGenericParameter {
272 return Kind == MemberKind.TypeParameter;
277 // Returns true for instances of Nullable<T>
279 public virtual bool IsNullableType {
284 state = value ? state | StateFlags.InflatedNullableType : state & ~StateFlags.InflatedNullableType;
288 public bool IsNested {
289 get { return declaringType != null && Kind != MemberKind.TypeParameter; }
292 public bool IsPointer {
294 return Kind == MemberKind.PointerType;
298 public bool IsSealed {
299 get { return (Modifiers & Modifiers.SEALED) != 0; }
302 public bool IsSpecialRuntimeType {
304 return (state & StateFlags.SpecialRuntimeType) != 0;
307 state = value ? state | StateFlags.SpecialRuntimeType : state & ~StateFlags.SpecialRuntimeType;
311 public bool IsStruct {
313 return Kind == MemberKind.Struct;
317 public bool IsStructOrEnum {
319 return (Kind & (MemberKind.Struct | MemberKind.Enum)) != 0;
323 public bool IsTypeBuilder {
328 var meta = GetMetaInfo().GetType ();
329 return meta == TypeBuilder || meta == GenericTypeBuilder;
335 // Whether a type is unmanaged. This is used by the unsafe code
337 public bool IsUnmanaged {
340 return ((ElementTypeSpec) this).Element.IsUnmanaged;
342 var ds = MemberDefinition as TypeDefinition;
344 return ds.IsUnmanagedType ();
346 if (Kind == MemberKind.Void)
349 if (Kind == MemberKind.TypeParameter)
352 if (IsNested && DeclaringType.IsGenericOrParentIsGeneric)
355 return IsValueType (this);
360 // A cache of all type members (including nested types)
362 public MemberCache MemberCache {
364 if (cache == null || (state & StateFlags.PendingMemberCacheMembers) != 0)
365 InitializeMemberCache (false);
371 throw new InternalErrorException ("Membercache reset");
377 public MemberCache MemberCacheTypes {
380 InitializeMemberCache (true);
386 public new ITypeDefinition MemberDefinition {
388 return (ITypeDefinition) definition;
392 // TODO: Wouldn't be better to rely on cast to InflatedTypeSpec and
393 // remove the property, YES IT WOULD !!!
394 public virtual TypeSpec[] TypeArguments {
395 get { return TypeSpec.EmptyTypes; }
400 public virtual bool AddInterface (TypeSpec iface)
402 if ((state & StateFlags.InterfacesExpanded) != 0)
403 throw new InternalErrorException ("Modifying expanded interface list");
405 if (ifaces == null) {
406 ifaces = new List<TypeSpec> { iface };
410 if (!ifaces.Contains (iface)) {
419 // Special version used during type definition
421 public bool AddInterfaceDefined (TypeSpec iface)
423 if (!AddInterface (iface))
427 // We can get into a situation where a type is inflated before
428 // its interfaces are resoved. Consider this situation
430 // class A<T> : X<A<int>>, IFoo {}
432 // When resolving base class of X`1 we inflate context type A`1
433 // All this happens before we even hit IFoo resolve. Without
434 // additional expansion any inside usage of A<T> would miss IFoo
435 // interface because it comes from early inflated A`1 definition.
437 if (inflated_instances != null) {
439 // Inflate only existing instances not any new instances added
440 // during AddInterface
442 var inflated_existing = inflated_instances.Values.ToArray ();
443 foreach (var inflated in inflated_existing) {
444 inflated.AddInterface (iface);
452 // Returns all type arguments, usefull for nested types
454 public static TypeSpec[] GetAllTypeArguments (TypeSpec type)
456 IList<TypeSpec> targs = TypeSpec.EmptyTypes;
459 if (type.Arity > 0) {
460 if (targs.Count == 0) {
461 targs = type.TypeArguments;
463 var list = targs as List<TypeSpec> ?? new List<TypeSpec> (targs);
464 list.AddRange (type.TypeArguments);
469 type = type.declaringType;
470 } while (type != null);
472 return targs as TypeSpec[] ?? ((List<TypeSpec>) targs).ToArray ();
475 public AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa)
477 if (Kind != MemberKind.Class)
478 throw new InternalErrorException ();
481 return Attribute.DefaultUsageAttribute;
483 AttributeUsageAttribute aua = null;
485 while (type != null) {
486 aua = type.MemberDefinition.GetAttributeUsage (pa);
490 type = type.BaseType;
497 // Return metadata information used during emit to describe the type
499 public virtual MetaType GetMetaInfo ()
504 public virtual TypeSpec GetDefinition ()
510 // Text representation of type used by documentation writer
512 public sealed override string GetSignatureForDocumentation ()
514 return GetSignatureForDocumentation (false);
517 public virtual string GetSignatureForDocumentation (bool explicitName)
519 StringBuilder sb = new StringBuilder ();
521 sb.Append (DeclaringType.GetSignatureForDocumentation (explicitName));
522 } else if (MemberDefinition.Namespace != null) {
523 sb.Append (explicitName ? MemberDefinition.Namespace.Replace ('.', '#') : MemberDefinition.Namespace);
527 sb.Append (explicitName ? "#" : ".");
531 if (this is InflatedTypeSpec) {
533 for (int i = 0; i < Arity; ++i) {
537 sb.Append (TypeArguments[i].GetSignatureForDocumentation (explicitName));
542 sb.Append (Arity.ToString ());
546 return sb.ToString ();
549 public override string GetSignatureForError ()
554 s = DeclaringType.GetSignatureForError ();
555 } else if (MemberDefinition is AnonymousTypeClass) {
556 return ((AnonymousTypeClass)MemberDefinition).GetSignatureForError ();
557 } else if (IsTupleType) {
558 return FormatTupleSignature ();
560 s = MemberDefinition.Namespace;
563 if (!string.IsNullOrEmpty (s))
566 return s + Name + GetTypeNameSignature ();
569 string FormatTupleSignature ()
571 var sb = new StringBuilder ();
573 for (int i = 0; i < TypeArguments.Length; ++i) {
577 sb.Append (TypeArguments[i].GetSignatureForError ());
581 return sb.ToString ();
584 public string GetSignatureForErrorIncludingAssemblyName ()
586 var imported = MemberDefinition.DeclaringAssembly as ImportedAssemblyDefinition;
588 var location = imported != null ?
589 System.IO.Path.GetFullPath (imported.Location) :
590 ((MemberCore)MemberDefinition).Location.NameFullPath;
592 return string.Format ("{0} [{1} -- {2}]", GetSignatureForError (),
593 MemberDefinition.DeclaringAssembly.FullName,
597 protected virtual string GetTypeNameSignature ()
602 return "<" + TypeManager.CSharpName (MemberDefinition.TypeParameters) + ">";
605 public bool ImplementsInterface (TypeSpec iface, bool variantly)
607 var ifaces = Interfaces;
608 if (ifaces != null) {
609 for (int i = 0; i < ifaces.Count; ++i) {
610 if (TypeSpecComparer.IsEqual (ifaces[i], iface))
613 if (variantly && TypeSpecComparer.Variant.IsEqual (ifaces[i], iface))
621 protected virtual void InitializeMemberCache (bool onlyTypes)
624 MemberDefinition.LoadMembers (this, onlyTypes, ref cache);
625 } catch (Exception e) {
626 throw new InternalErrorException (e, "Unexpected error when loading type `{0}'", GetSignatureForError ());
630 state |= StateFlags.PendingMemberCacheMembers;
632 state &= ~StateFlags.PendingMemberCacheMembers;
636 // Is @baseClass base implementation of @type. With enabled @dynamicIsEqual the slower
637 // comparison is used to hide differences between `object' and `dynamic' for generic
638 // types. Should not be used for comparisons where G<object> != G<dynamic>
640 public static bool IsBaseClass (TypeSpec type, TypeSpec baseClass, bool dynamicIsObject)
642 if (dynamicIsObject && baseClass.IsGeneric) {
644 // Returns true for a hierarchies like this when passing baseClass of A<dynamic>
646 // class B : A<object> {}
648 type = type.BaseType;
649 while (type != null) {
650 if (TypeSpecComparer.IsEqual (type, baseClass))
653 type = type.BaseType;
659 while (type != null) {
660 type = type.BaseType;
661 if (type == baseClass)
668 public static bool IsReferenceType (TypeSpec t)
671 case MemberKind.TypeParameter:
672 return ((TypeParameterSpec) t).IsReferenceType;
673 case MemberKind.Struct:
674 case MemberKind.Enum:
675 case MemberKind.Void:
676 case MemberKind.PointerType:
678 case MemberKind.InternalCompilerType:
680 // Null is considered to be a reference type
682 return t == InternalType.NullLiteral || t.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
688 public static bool IsNonNullableValueType (TypeSpec t)
691 case MemberKind.TypeParameter:
692 return ((TypeParameterSpec) t).IsValueType;
693 case MemberKind.Struct:
694 return !t.IsNullableType;
695 case MemberKind.Enum:
702 public static bool IsValueType (TypeSpec t)
705 case MemberKind.TypeParameter:
706 return ((TypeParameterSpec) t).IsValueType;
707 case MemberKind.Struct:
708 case MemberKind.Enum:
715 public override MemberSpec InflateMember (TypeParameterInflator inflator)
717 var targs = IsGeneric ? MemberDefinition.TypeParameters : TypeSpec.EmptyTypes;
720 // When inflating nested type from inside the type instance will be same
721 // because type parameters are same for all nested types
723 if (DeclaringType == inflator.TypeInstance) {
724 return MakeGenericType (inflator.Context, targs);
727 return new InflatedTypeSpec (inflator.Context, this, inflator.TypeInstance, targs);
731 // Inflates current type using specific type arguments
733 public InflatedTypeSpec MakeGenericType (IModuleContext context, TypeSpec[] targs)
735 if (targs.Length == 0 && !IsNested)
736 throw new ArgumentException ("Empty type arguments for type " + GetSignatureForError ());
738 InflatedTypeSpec instance;
740 if (inflated_instances == null) {
741 inflated_instances = new Dictionary<TypeSpec[], InflatedTypeSpec> (TypeSpecComparer.Default);
744 instance = this as InflatedTypeSpec;
745 if (instance != null) {
747 // Nested types could be inflated on already inflated instances
748 // Caching this type ensured we are using same instance for
749 // inside/outside inflation using local type parameters
751 inflated_instances.Add (TypeArguments, instance);
756 if (!inflated_instances.TryGetValue (targs, out instance)) {
757 if (GetDefinition () != this && !IsNested)
758 throw new InternalErrorException ("`{0}' must be type definition or nested non-inflated type to MakeGenericType",
759 GetSignatureForError ());
761 instance = new InflatedTypeSpec (context, this, declaringType, targs);
762 inflated_instances.Add (targs, instance);
768 public virtual TypeSpec Mutate (TypeParameterMutator mutator)
773 public override List<MissingTypeSpecReference> ResolveMissingDependencies (MemberSpec caller)
775 List<MissingTypeSpecReference> missing = null;
777 if (Kind == MemberKind.MissingType) {
778 missing = new List<MissingTypeSpecReference> ();
779 missing.Add (new MissingTypeSpecReference (this, caller));
783 foreach (var targ in TypeArguments) {
784 if (targ.Kind == MemberKind.MissingType) {
786 missing = new List<MissingTypeSpecReference> ();
788 missing.Add (new MissingTypeSpecReference (targ, caller));
792 if (Interfaces != null) {
793 foreach (var iface in Interfaces) {
794 if (iface.Kind == MemberKind.MissingType) {
796 missing = new List<MissingTypeSpecReference> ();
798 missing.Add (new MissingTypeSpecReference (iface, caller));
803 if (MemberDefinition.TypeParametersCount > 0) {
804 foreach (var tp in MemberDefinition.TypeParameters) {
805 var tp_missing = tp.GetMissingDependencies (this);
806 if (tp_missing != null) {
808 missing = new List<MissingTypeSpecReference> ();
810 missing.AddRange (tp_missing);
815 if (missing != null || BaseType == null)
818 return BaseType.ResolveMissingDependencies (this);
821 public void SetMetaInfo (MetaType info)
823 if (this.info != null)
824 throw new InternalErrorException ("MetaInfo reset");
829 public void SetExtensionMethodContainer ()
831 modifiers |= Modifiers.METHOD_EXTENSION;
834 public void UpdateInflatedInstancesBaseType ()
837 // When nested class has a partial part the situation where parent type
838 // is inflated before its base type is defined can occur. In such case
839 // all inflated (should be only 1) instansted need to be updated
841 // partial class A<T> {
842 // partial class B : A<int> { }
845 // partial class A<T> : X {}
847 if (inflated_instances == null)
850 foreach (var inflated in inflated_instances) {
852 // Don't need to inflate possible generic type because for now the method
853 // is always used from within the nested type
855 inflated.Value.BaseType = base_type;
861 // Special version used for types which must exist in corlib or
862 // the compiler cannot work
864 public sealed class BuiltinTypeSpec : TypeSpec
870 // Ordered carefully for fast compares
898 MulticastDelegate = 23,
911 readonly string name;
913 public BuiltinTypeSpec (MemberKind kind, string ns, string name, Type builtinKind)
914 : base (kind, null, null, null, Modifiers.PUBLIC)
916 this.type = builtinKind;
921 public BuiltinTypeSpec (string name, Type builtinKind)
922 : this (MemberKind.InternalCompilerType, "", name, builtinKind)
924 // Make all internal types CLS-compliant, non-obsolete, compact
925 state = (state & ~(StateFlags.CLSCompliant_Undetected | StateFlags.Obsolete_Undetected | StateFlags.MissingDependency_Undetected)) | StateFlags.CLSCompliant;
930 public override int Arity {
936 public override BuiltinTypeSpec.Type BuiltinType {
942 public string FullName {
944 return ns + '.' + name;
948 public override string Name {
954 public string Namespace {
962 public static bool IsPrimitiveType (TypeSpec type)
964 return type.BuiltinType >= Type.FirstPrimitive && type.BuiltinType <= Type.LastPrimitive;
967 public static bool IsPrimitiveTypeOrDecimal (TypeSpec type)
969 return type.BuiltinType >= Type.FirstPrimitive && type.BuiltinType <= Type.Decimal;
972 public override string GetSignatureForError ()
975 case "Int32": return "int";
976 case "Int64": return "long";
977 case "String": return "string";
978 case "Boolean": return "bool";
979 case "Void": return "void";
980 case "Object": return "object";
981 case "UInt32": return "uint";
982 case "Int16": return "short";
983 case "UInt16": return "ushort";
984 case "UInt64": return "ulong";
985 case "Single": return "float";
986 case "Double": return "double";
987 case "Decimal": return "decimal";
988 case "Char": return "char";
989 case "Byte": return "byte";
990 case "SByte": return "sbyte";
1000 // Returns the size of type if known, otherwise, 0
1002 public static int GetSize (TypeSpec type)
1004 switch (type.BuiltinType) {
1028 public void SetDefinition (ITypeDefinition td, MetaType type, Modifiers mod)
1030 this.definition = td;
1032 this.modifiers |= (mod & ~Modifiers.AccessibilityMask);
1035 public void SetDefinition (TypeSpec ts)
1037 this.definition = ts.MemberDefinition;
1038 this.info = ts.GetMetaInfo ();
1039 this.BaseType = ts.BaseType;
1040 this.Interfaces = ts.Interfaces;
1041 this.modifiers = ts.Modifiers;
1046 // Various type comparers used by compiler
1048 static class TypeSpecComparer
1051 // Does strict reference comparion only
1053 public static readonly DefaultImpl Default = new DefaultImpl ();
1055 public class DefaultImpl : IEqualityComparer<TypeSpec[]>
1057 #region IEqualityComparer<TypeSpec[]> Members
1059 bool IEqualityComparer<TypeSpec[]>.Equals (TypeSpec[] x, TypeSpec[] y)
1064 if (x.Length != y.Length)
1067 for (int i = 0; i < x.Length; ++i)
1074 int IEqualityComparer<TypeSpec[]>.GetHashCode (TypeSpec[] obj)
1077 for (int i = 0; i < obj.Length; ++i)
1078 hash = (hash << 5) - hash + obj[i].GetHashCode ();
1087 // When comparing type signature of overrides or overloads
1088 // this version tolerates different MVARs at same position
1090 public static class Override
1092 public static bool IsEqual (TypeSpec a, TypeSpec b)
1098 // Consider the following example:
1100 // public abstract class A
1102 // public abstract T Foo<T>();
1105 // public class B : A
1107 // public override U Foo<T>() { return default (U); }
1110 // Here, `T' and `U' are method type parameters from different methods
1111 // (A.Foo and B.Foo), so both `==' and Equals() will fail.
1113 // However, since we're determining whether B.Foo() overrides A.Foo(),
1114 // we need to do a signature based comparision and consider them equal.
1117 var tp_a = a as TypeParameterSpec;
1119 var tp_b = b as TypeParameterSpec;
1120 return tp_b != null && tp_a.IsMethodOwned == tp_b.IsMethodOwned && tp_a.DeclaredPosition == tp_b.DeclaredPosition;
1123 var ac_a = a as ArrayContainer;
1125 var ac_b = b as ArrayContainer;
1126 return ac_b != null && ac_a.Rank == ac_b.Rank && IsEqual (ac_a.Element, ac_b.Element);
1129 if (a.BuiltinType == BuiltinTypeSpec.Type.Dynamic || b.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1130 return b.BuiltinType == BuiltinTypeSpec.Type.Object || a.BuiltinType == BuiltinTypeSpec.Type.Object;
1132 if (a.MemberDefinition != b.MemberDefinition)
1136 for (int i = 0; i < a.TypeArguments.Length; ++i) {
1137 if (!IsEqual (a.TypeArguments[i], b.TypeArguments[i]))
1141 a = a.DeclaringType;
1142 b = b.DeclaringType;
1143 } while (a != null);
1148 public static bool IsEqual (TypeSpec[] a, TypeSpec[] b)
1153 if (a.Length != b.Length)
1156 for (int i = 0; i < a.Length; ++i) {
1157 if (!IsEqual (a[i], b[i]))
1166 // Compares unordered arrays
1168 public static bool IsSame (TypeSpec[] a, TypeSpec[] b)
1173 if (a == null || b == null || a.Length != b.Length)
1176 for (int ai = 0; ai < a.Length; ++ai) {
1178 for (int bi = 0; bi < b.Length; ++bi) {
1179 if (IsEqual (a[ai], b[bi])) {
1192 public static bool IsEqual (AParametersCollection a, AParametersCollection b)
1197 if (a.Count != b.Count)
1200 for (int i = 0; i < a.Count; ++i) {
1201 if (!IsEqual (a.Types[i], b.Types[i]))
1204 if ((a.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (b.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
1213 // Type variance equality comparison
1215 public static class Variant
1217 public static bool IsEqual (TypeSpec type1, TypeSpec type2)
1219 if (!type1.IsGeneric || !type2.IsGeneric)
1222 var target_type_def = type2.MemberDefinition;
1223 if (type1.MemberDefinition != target_type_def)
1226 var t1_targs = type1.TypeArguments;
1227 var t2_targs = type2.TypeArguments;
1228 var targs_definition = target_type_def.TypeParameters;
1230 if (!type1.IsInterface && !type1.IsDelegate) {
1234 for (int i = 0; i < targs_definition.Length; ++i) {
1235 if (TypeSpecComparer.IsEqual (t1_targs[i], t2_targs[i]))
1238 Variance v = targs_definition[i].Variance;
1239 if (v == Variance.None) {
1243 if (v == Variance.Covariant) {
1244 if (!Convert.ImplicitReferenceConversionExists (t1_targs[i], t2_targs[i]))
1246 } else if (!Convert.ImplicitReferenceConversionExists (t2_targs[i], t1_targs[i])) {
1256 // Checks whether two generic instances may become equal for some
1257 // particular instantiation (26.3.1).
1259 public static class Unify
1262 // Either @a or @b must be generic type
1264 public static bool IsEqual (TypeSpec a, TypeSpec b)
1266 if (a.MemberDefinition != b.MemberDefinition) {
1267 var base_ifaces = a.Interfaces;
1268 if (base_ifaces != null) {
1269 foreach (var base_iface in base_ifaces) {
1270 if (base_iface.Arity > 0 && IsEqual (base_iface, b))
1278 var ta = a.TypeArguments;
1279 var tb = b.TypeArguments;
1280 for (int i = 0; i < ta.Length; i++) {
1281 if (!MayBecomeEqualGenericTypes (ta[i], tb[i]))
1285 if (a.IsNested && b.IsNested)
1286 return IsEqual (a.DeclaringType, b.DeclaringType);
1291 static bool ContainsTypeParameter (TypeSpec tparam, TypeSpec type)
1293 TypeSpec[] targs = type.TypeArguments;
1294 for (int i = 0; i < targs.Length; i++) {
1295 if (tparam == targs[i])
1298 if (ContainsTypeParameter (tparam, targs[i]))
1306 /// Check whether `a' and `b' may become equal generic types.
1307 /// The algorithm to do that is a little bit complicated.
1309 static bool MayBecomeEqualGenericTypes (TypeSpec a, TypeSpec b)
1311 if (a.IsGenericParameter) {
1313 // If a is an array of a's type, they may never
1320 // If b is a generic parameter or an actual type,
1321 // they may become equal:
1323 // class X<T,U> : I<T>, I<U>
1324 // class X<T> : I<T>, I<float>
1326 if (b.IsGenericParameter)
1327 return a != b && a.DeclaringType == b.DeclaringType;
1330 // We're now comparing a type parameter with a
1331 // generic instance. They may become equal unless
1332 // the type parameter appears anywhere in the
1333 // generic instance:
1335 // class X<T,U> : I<T>, I<X<U>>
1336 // -> error because you could instanciate it as
1339 // class X<T> : I<T>, I<X<T>> -> ok
1342 return !ContainsTypeParameter (a, b);
1345 if (b.IsGenericParameter)
1346 return MayBecomeEqualGenericTypes (b, a);
1349 // At this point, neither a nor b are a type parameter.
1351 // If one of them is a generic instance, compare them (if the
1352 // other one is not a generic instance, they can never
1355 if (TypeManager.IsGenericType (a) || TypeManager.IsGenericType (b))
1356 return IsEqual (a, b);
1359 // If both of them are arrays.
1361 var a_ac = a as ArrayContainer;
1363 var b_ac = b as ArrayContainer;
1364 if (b_ac == null || a_ac.Rank != b_ac.Rank)
1367 return MayBecomeEqualGenericTypes (a_ac.Element, b_ac.Element);
1371 // Ok, two ordinary types.
1377 public static bool Equals (TypeSpec[] x, TypeSpec[] y)
1382 if (x.Length != y.Length)
1385 for (int i = 0; i < x.Length; ++i)
1386 if (!IsEqual (x[i], y[i]))
1393 // Identity type conversion
1395 // Default reference comparison, it has to be used when comparing
1396 // two possible dynamic/internal types
1398 public static bool IsEqual (TypeSpec a, TypeSpec b)
1401 // This also rejects dynamic == dynamic
1402 return a.Kind != MemberKind.InternalCompilerType || a.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
1405 if (a == null || b == null)
1409 var a_a = (ArrayContainer) a;
1410 var b_a = b as ArrayContainer;
1414 return a_a.Rank == b_a.Rank && IsEqual (a_a.Element, b_a.Element);
1417 if (!a.IsGeneric || !b.IsGeneric) {
1419 // object and dynamic are considered equivalent there is an identity conversion
1420 // between object and dynamic, and between constructed types that are the same
1421 // when replacing all occurences of dynamic with object.
1423 if (a.BuiltinType == BuiltinTypeSpec.Type.Dynamic || b.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1424 return b.BuiltinType == BuiltinTypeSpec.Type.Object || a.BuiltinType == BuiltinTypeSpec.Type.Object;
1429 if (a.MemberDefinition != b.MemberDefinition)
1433 if (!Equals (a.TypeArguments, b.TypeArguments))
1436 a = a.DeclaringType;
1437 b = b.DeclaringType;
1438 } while (a != null);
1444 public interface ITypeDefinition : IMemberDefinition
1446 IAssemblyDefinition DeclaringAssembly { get; }
1447 string Namespace { get; }
1448 bool IsPartial { get; }
1449 bool IsComImport { get; }
1450 bool IsTypeForwarder { get; }
1451 bool IsCyclicTypeForwarder { get; }
1452 int TypeParametersCount { get; }
1453 TypeParameterSpec[] TypeParameters { get; }
1455 TypeSpec GetAttributeCoClass ();
1456 string GetAttributeDefaultMember ();
1457 AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa);
1458 bool IsInternalAsPublic (IAssemblyDefinition assembly);
1459 void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache);
1462 class InternalType : TypeSpec, ITypeDefinition
1464 public static readonly InternalType AnonymousMethod = new InternalType ("anonymous method");
1465 public static readonly InternalType Arglist = new InternalType ("__arglist");
1466 public static readonly InternalType MethodGroup = new InternalType ("method group");
1467 public static readonly InternalType NullLiteral = new InternalType ("null");
1468 public static readonly InternalType FakeInternalType = new InternalType ("<fake$type>");
1469 public static readonly InternalType Namespace = new InternalType ("<namespace>");
1470 public static readonly InternalType ErrorType = new InternalType ("<error>");
1471 public static readonly InternalType VarOutType = new InternalType ("var out");
1472 public static readonly InternalType ThrowExpr = new InternalType ("throw expression");
1474 readonly string name;
1476 InternalType (string name)
1477 : base (MemberKind.InternalCompilerType, null, null, null, Modifiers.PUBLIC)
1480 this.definition = this;
1481 cache = MemberCache.Empty;
1483 // Make all internal types CLS-compliant, non-obsolete
1484 state = (state & ~(StateFlags.CLSCompliant_Undetected | StateFlags.Obsolete_Undetected | StateFlags.MissingDependency_Undetected)) | StateFlags.CLSCompliant;
1489 public override int Arity {
1495 IAssemblyDefinition ITypeDefinition.DeclaringAssembly {
1497 throw new NotImplementedException ();
1501 bool ITypeDefinition.IsComImport {
1507 bool IMemberDefinition.IsImported {
1513 bool ITypeDefinition.IsPartial {
1519 bool ITypeDefinition.IsTypeForwarder {
1525 bool ITypeDefinition.IsCyclicTypeForwarder {
1531 public override string Name {
1537 string ITypeDefinition.Namespace {
1543 int ITypeDefinition.TypeParametersCount {
1549 TypeParameterSpec[] ITypeDefinition.TypeParameters {
1557 public override string GetSignatureForError ()
1562 #region ITypeDefinition Members
1564 TypeSpec ITypeDefinition.GetAttributeCoClass ()
1569 string ITypeDefinition.GetAttributeDefaultMember ()
1574 AttributeUsageAttribute ITypeDefinition.GetAttributeUsage (PredefinedAttribute pa)
1579 bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly)
1581 throw new NotImplementedException ();
1584 void ITypeDefinition.LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
1586 throw new NotImplementedException ();
1589 string[] IMemberDefinition.ConditionalConditions ()
1594 ObsoleteAttribute IMemberDefinition.GetAttributeObsolete ()
1599 bool? IMemberDefinition.CLSAttributeValue {
1605 void IMemberDefinition.SetIsAssigned ()
1609 void IMemberDefinition.SetIsUsed ()
1615 public static bool HasNoType (TypeSpec type)
1617 return type == AnonymousMethod || type == MethodGroup || type == NullLiteral || type == ThrowExpr;
1622 // Common base class for composite types
1624 public abstract class ElementTypeSpec : TypeSpec, ITypeDefinition
1626 protected ElementTypeSpec (MemberKind kind, TypeSpec element, MetaType info)
1627 : base (kind, element.DeclaringType, null, info, element.Modifiers)
1629 this.Element = element;
1631 state &= ~SharedStateFlags;
1632 state |= (element.state & SharedStateFlags);
1634 if (element.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1635 state |= StateFlags.HasDynamicElement;
1637 // Has to use its own type definition instead of just element definition to
1638 // correctly identify itself for cases like x.MemberDefininition == predefined.MemberDefinition
1639 this.definition = this;
1641 cache = MemberCache.Empty;
1646 public TypeSpec Element { get; private set; }
1648 public override IList<TypeSpec> Interfaces {
1650 throw new NotSupportedException ();
1654 bool ITypeDefinition.IsComImport {
1660 bool ITypeDefinition.IsPartial {
1666 bool ITypeDefinition.IsTypeForwarder {
1672 bool ITypeDefinition.IsCyclicTypeForwarder {
1678 public override string Name {
1680 throw new NotSupportedException ();
1686 public override void CheckObsoleteness (IMemberContext mc, Location loc)
1688 Element.CheckObsoleteness (mc, loc);
1691 public override ObsoleteAttribute GetAttributeObsolete ()
1693 return Element.GetAttributeObsolete ();
1696 protected virtual string GetPostfixSignature ()
1701 public override string GetSignatureForDocumentation (bool explicitName)
1703 return Element.GetSignatureForDocumentation (explicitName) + GetPostfixSignature ();
1706 public override string GetSignatureForError ()
1708 return Element.GetSignatureForError () + GetPostfixSignature ();
1711 public override TypeSpec Mutate (TypeParameterMutator mutator)
1713 var me = Element.Mutate (mutator);
1717 var mutated = (ElementTypeSpec) MemberwiseClone ();
1718 mutated.Element = me;
1719 mutated.info = null;
1723 #region ITypeDefinition Members
1725 IAssemblyDefinition ITypeDefinition.DeclaringAssembly {
1727 return Element.MemberDefinition.DeclaringAssembly;
1731 bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly)
1733 return Element.MemberDefinition.IsInternalAsPublic (assembly);
1736 public string Namespace {
1737 get { throw new NotImplementedException (); }
1740 public int TypeParametersCount {
1746 public TypeParameterSpec[] TypeParameters {
1748 throw new NotSupportedException ();
1752 public TypeSpec GetAttributeCoClass ()
1754 return Element.MemberDefinition.GetAttributeCoClass ();
1757 public string GetAttributeDefaultMember ()
1759 return Element.MemberDefinition.GetAttributeDefaultMember ();
1762 public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
1764 Element.MemberDefinition.LoadMembers (declaringType, onlyTypes, ref cache);
1767 public bool IsImported {
1769 return Element.MemberDefinition.IsImported;
1773 public string[] ConditionalConditions ()
1775 return Element.MemberDefinition.ConditionalConditions ();
1778 bool? IMemberDefinition.CLSAttributeValue {
1780 return Element.MemberDefinition.CLSAttributeValue;
1784 public void SetIsAssigned ()
1786 Element.MemberDefinition.SetIsAssigned ();
1789 public void SetIsUsed ()
1791 Element.MemberDefinition.SetIsUsed ();
1797 public class ArrayContainer : ElementTypeSpec
1799 public struct TypeRankPair : IEquatable<TypeRankPair>
1804 public TypeRankPair (TypeSpec ts, int rank)
1810 public override int GetHashCode ()
1812 return ts.GetHashCode () ^ rank.GetHashCode ();
1815 #region IEquatable<Tuple<T1,T2>> Members
1817 public bool Equals (TypeRankPair other)
1819 return other.ts == ts && other.rank == rank;
1826 readonly ModuleContainer module;
1828 ArrayContainer (ModuleContainer module, TypeSpec element, int rank)
1829 : base (MemberKind.ArrayType, element, null)
1831 this.module = module;
1835 public override IList<TypeSpec> Interfaces {
1837 return BaseType.Interfaces;
1847 public MethodInfo GetConstructor ()
1849 var mb = module.Builder;
1851 var arg_types = new MetaType[rank];
1852 for (int i = 0; i < rank; i++)
1853 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1855 var ctor = mb.GetArrayMethod (
1856 GetMetaInfo (), Constructor.ConstructorName,
1857 CallingConventions.HasThis,
1863 public MethodInfo GetAddressMethod ()
1865 var mb = module.Builder;
1867 var arg_types = new MetaType[rank];
1868 for (int i = 0; i < rank; i++)
1869 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1871 var address = mb.GetArrayMethod (
1872 GetMetaInfo (), "Address",
1873 CallingConventions.HasThis | CallingConventions.Standard,
1874 ReferenceContainer.MakeType (module, Element).GetMetaInfo (), arg_types);
1879 public MethodInfo GetGetMethod ()
1881 var mb = module.Builder;
1883 var arg_types = new MetaType[rank];
1884 for (int i = 0; i < rank; i++)
1885 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1887 var get = mb.GetArrayMethod (
1888 GetMetaInfo (), "Get",
1889 CallingConventions.HasThis | CallingConventions.Standard,
1890 Element.GetMetaInfo (), arg_types);
1895 public MethodInfo GetSetMethod ()
1897 var mb = module.Builder;
1899 var arg_types = new MetaType[rank + 1];
1900 for (int i = 0; i < rank; i++)
1901 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1903 arg_types[rank] = Element.GetMetaInfo ();
1905 var set = mb.GetArrayMethod (
1906 GetMetaInfo (), "Set",
1907 CallingConventions.HasThis | CallingConventions.Standard,
1908 module.Compiler.BuiltinTypes.Void.GetMetaInfo (), arg_types);
1913 public override MetaType GetMetaInfo ()
1917 info = Element.GetMetaInfo ().MakeArrayType ();
1919 info = Element.GetMetaInfo ().MakeArrayType (rank);
1925 protected override string GetPostfixSignature()
1927 return GetPostfixSignature (rank);
1930 public static string GetPostfixSignature (int rank)
1932 StringBuilder sb = new StringBuilder ();
1934 for (int i = 1; i < rank; i++) {
1939 return sb.ToString ();
1942 public override string GetSignatureForDocumentation (bool explicitName)
1944 StringBuilder sb = new StringBuilder ();
1945 GetElementSignatureForDocumentation (sb, explicitName);
1946 return sb.ToString ();
1949 void GetElementSignatureForDocumentation (StringBuilder sb, bool explicitName)
1951 var ac = Element as ArrayContainer;
1953 sb.Append (Element.GetSignatureForDocumentation (explicitName));
1955 ac.GetElementSignatureForDocumentation (sb, explicitName);
1958 sb.Append (GetPostfixSignature (rank));
1961 for (int i = 1; i < rank; i++) {
1971 public static ArrayContainer MakeType (ModuleContainer module, TypeSpec element)
1973 return MakeType (module, element, 1);
1976 public static ArrayContainer MakeType (ModuleContainer module, TypeSpec element, int rank)
1979 var key = new TypeRankPair (element, rank);
1980 if (!module.ArrayTypesCache.TryGetValue (key, out ac)) {
1981 ac = new ArrayContainer (module, element, rank);
1982 ac.BaseType = module.Compiler.BuiltinTypes.Array;
1984 module.ArrayTypesCache.Add (key, ac);
1990 public override List<MissingTypeSpecReference> ResolveMissingDependencies (MemberSpec caller)
1992 return Element.ResolveMissingDependencies (caller);
1996 [System.Diagnostics.DebuggerDisplay("{DisplayDebugInfo()}")]
1997 class ReferenceContainer : ElementTypeSpec
1999 ReferenceContainer (TypeSpec element)
2000 : base (MemberKind.ByRef, element, null)
2004 public override IList<TypeSpec> Interfaces {
2010 string DisplayDebugInfo()
2012 return "ref " + GetSignatureForError();
2015 public override MetaType GetMetaInfo ()
2018 info = Element.GetMetaInfo ().MakeByRefType ();
2024 public override string GetSignatureForError ()
2026 return Element.GetSignatureForError ();
2029 public static ReferenceContainer MakeType (ModuleContainer module, TypeSpec element)
2031 if (element.Kind == MemberKind.ByRef)
2032 throw new ArgumentException ();
2034 ReferenceContainer pc;
2035 if (!module.ReferenceTypesCache.TryGetValue (element, out pc)) {
2036 pc = new ReferenceContainer (element);
2037 module.ReferenceTypesCache.Add (element, pc);
2044 class PointerContainer : ElementTypeSpec
2046 private PointerContainer (TypeSpec element)
2047 : base (MemberKind.PointerType, element, null)
2049 // It's never CLS-Compliant
2050 state &= ~StateFlags.CLSCompliant_Undetected;
2053 public override IList<TypeSpec> Interfaces {
2059 public override MetaType GetMetaInfo ()
2062 info = Element.GetMetaInfo ().MakePointerType ();
2068 protected override string GetPostfixSignature()
2073 public static PointerContainer MakeType (ModuleContainer module, TypeSpec element)
2075 PointerContainer pc;
2076 if (!module.PointerTypesCache.TryGetValue (element, out pc)) {
2077 pc = new PointerContainer (element);
2078 module.PointerTypesCache.Add (element, pc);
2085 public class MissingTypeSpecReference
2087 public MissingTypeSpecReference (TypeSpec type, MemberSpec caller)
2093 public TypeSpec Type { get; private set; }
2094 public MemberSpec Caller { get; private set; }