2 // typespec.cs: Type specification
4 // Authors: Marek Safar (marek.safar@gmail.com)
6 // Dual licensed under the terms of the MIT X11 or GNU GPL
8 // Copyright 2010 Novell, Inc
9 // Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
13 using System.Collections.Generic;
17 using MetaType = IKVM.Reflection.Type;
18 using IKVM.Reflection;
20 using MetaType = System.Type;
21 using System.Reflection;
26 public class TypeSpec : MemberSpec
28 protected MetaType info;
29 protected MemberCache cache;
30 protected IList<TypeSpec> ifaces;
33 Dictionary<TypeSpec[], InflatedTypeSpec> inflated_instances;
35 public static readonly TypeSpec[] EmptyTypes = new TypeSpec[0];
38 // Reflection Emit hacking
39 static readonly Type TypeBuilder;
40 static readonly Type GenericTypeBuilder;
44 var assembly = typeof (object).Assembly;
45 TypeBuilder = assembly.GetType ("System.Reflection.Emit.TypeBuilder");
46 GenericTypeBuilder = assembly.GetType ("System.Reflection.MonoGenericClass");
47 if (GenericTypeBuilder == null)
48 GenericTypeBuilder = assembly.GetType ("System.Reflection.Emit.TypeBuilderInstantiation");
52 public TypeSpec (MemberKind kind, TypeSpec declaringType, ITypeDefinition definition, MetaType info, Modifiers modifiers)
53 : base (kind, declaringType, definition, modifiers)
55 this.declaringType = declaringType;
58 if (definition != null && definition.TypeParametersCount > 0)
59 state |= StateFlags.IsGeneric;
64 public override int Arity {
66 return MemberDefinition.TypeParametersCount;
70 public virtual TypeSpec BaseType {
79 public virtual BuiltinTypeSpec.Type BuiltinType {
81 return BuiltinTypeSpec.Type.None;
85 public bool HasDynamicElement {
87 return (state & StateFlags.HasDynamicElement) != 0;
91 public virtual IList<TypeSpec> Interfaces {
100 public bool IsArray {
102 return Kind == MemberKind.ArrayType;
106 public bool IsAttribute {
113 if (type.BuiltinType == BuiltinTypeSpec.Type.Attribute)
119 type = type.base_type;
120 } while (type != null);
126 public bool IsInterface {
128 return Kind == MemberKind.Interface;
132 public bool IsClass {
134 return Kind == MemberKind.Class;
138 public bool IsConstantCompatible {
140 if ((Kind & (MemberKind.Enum | MemberKind.Class | MemberKind.Interface | MemberKind.Delegate | MemberKind.ArrayType)) != 0)
143 switch (BuiltinType) {
144 case BuiltinTypeSpec.Type.Int:
145 case BuiltinTypeSpec.Type.UInt:
146 case BuiltinTypeSpec.Type.Long:
147 case BuiltinTypeSpec.Type.ULong:
148 case BuiltinTypeSpec.Type.Float:
149 case BuiltinTypeSpec.Type.Double:
150 case BuiltinTypeSpec.Type.Char:
151 case BuiltinTypeSpec.Type.Short:
152 case BuiltinTypeSpec.Type.Decimal:
153 case BuiltinTypeSpec.Type.Bool:
154 case BuiltinTypeSpec.Type.SByte:
155 case BuiltinTypeSpec.Type.Byte:
156 case BuiltinTypeSpec.Type.UShort:
157 case BuiltinTypeSpec.Type.Dynamic:
165 public bool IsDelegate {
167 return Kind == MemberKind.Delegate;
172 // Returns true for instances of Expression<T>
174 public virtual bool IsExpressionTreeType {
179 state = value ? state | StateFlags.InflatedExpressionType : state & ~StateFlags.InflatedExpressionType;
185 return Kind == MemberKind.Enum;
190 // Returns true for instances of IList<T>, IEnumerable<T>, ICollection<T>
192 public virtual bool IsGenericIterateInterface {
197 state = value ? state | StateFlags.GenericIterateInterface : state & ~StateFlags.GenericIterateInterface;
202 // Returns true for instances of System.Threading.Tasks.Task<T>
204 public virtual bool IsGenericTask {
209 state = value ? state | StateFlags.GenericTask : state & ~StateFlags.GenericTask;
213 // TODO: Should probably do
214 // IsGenericType -- recursive
215 // HasTypeParameter -- non-recursive
216 public bool IsGenericOrParentIsGeneric {
222 ts = ts.declaringType;
223 } while (ts != null);
229 public bool IsGenericParameter {
231 return Kind == MemberKind.TypeParameter;
236 // Returns true for instances of Nullable<T>
238 public virtual bool IsNullableType {
243 state = value ? state | StateFlags.InflatedNullableType : state & ~StateFlags.InflatedNullableType;
247 public bool IsNested {
248 get { return declaringType != null && Kind != MemberKind.TypeParameter; }
251 public bool IsPointer {
253 return Kind == MemberKind.PointerType;
257 public bool IsSealed {
258 get { return (Modifiers & Modifiers.SEALED) != 0; }
261 public bool IsSpecialRuntimeType {
263 return (state & StateFlags.SpecialRuntimeType) != 0;
266 state = value ? state | StateFlags.SpecialRuntimeType : state & ~StateFlags.SpecialRuntimeType;
270 public bool IsStruct {
272 return Kind == MemberKind.Struct;
276 public bool IsTypeBuilder {
281 var meta = GetMetaInfo().GetType ();
282 return meta == TypeBuilder || meta == GenericTypeBuilder;
288 // Whether a type is unmanaged. This is used by the unsafe code
290 public bool IsUnmanaged {
293 return ((ElementTypeSpec) this).Element.IsUnmanaged;
295 var ds = MemberDefinition as TypeDefinition;
297 return ds.IsUnmanagedType ();
299 if (Kind == MemberKind.Void)
302 if (IsNested && DeclaringType.IsGenericOrParentIsGeneric)
305 return IsValueType (this);
309 public MemberCache MemberCache {
311 if (cache == null || (state & StateFlags.PendingMemberCacheMembers) != 0)
312 InitializeMemberCache (false);
318 throw new InternalErrorException ("Membercache reset");
324 public MemberCache MemberCacheTypes {
327 InitializeMemberCache (true);
333 public new ITypeDefinition MemberDefinition {
335 return (ITypeDefinition) definition;
339 // TODO: Wouldn't be better to rely on cast to InflatedTypeSpec and
340 // remove the property, YES IT WOULD !!!
341 public virtual TypeSpec[] TypeArguments {
342 get { return TypeSpec.EmptyTypes; }
347 public bool AddInterface (TypeSpec iface)
349 if ((state & StateFlags.InterfacesExpanded) != 0)
350 throw new InternalErrorException ("Modifying expanded interface list");
352 if (ifaces == null) {
353 ifaces = new List<TypeSpec> () { iface };
357 if (!ifaces.Contains (iface)) {
366 // Special version used during type definition
368 public bool AddInterfaceDefined (TypeSpec iface)
370 if (!AddInterface (iface))
374 // We can get into a situation where a type is inflated before
375 // its interfaces are resoved. Consider this situation
377 // class A<T> : X<A<int>>, IFoo {}
379 // When resolving base class of X`1 we inflate context type A`1
380 // All this happens before we even hit IFoo resolve. Without
381 // additional expansion any inside usage of A<T> would miss IFoo
382 // interface because it comes from early inflated TypeSpec
384 if (inflated_instances != null) {
385 foreach (var inflated in inflated_instances) {
386 inflated.Value.AddInterface (iface);
394 // Returns all type arguments, usefull for nested types
396 public static TypeSpec[] GetAllTypeArguments (TypeSpec type)
398 IList<TypeSpec> targs = TypeSpec.EmptyTypes;
401 if (type.Arity > 0) {
402 if (targs.Count == 0) {
403 targs = type.TypeArguments;
405 var list = targs as List<TypeSpec> ?? new List<TypeSpec> (targs);
406 list.AddRange (type.TypeArguments);
411 type = type.declaringType;
412 } while (type != null);
414 return targs as TypeSpec[] ?? ((List<TypeSpec>) targs).ToArray ();
417 public AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa)
419 if (Kind != MemberKind.Class)
420 throw new InternalErrorException ();
423 return Attribute.DefaultUsageAttribute;
425 AttributeUsageAttribute aua = null;
427 while (type != null) {
428 aua = type.MemberDefinition.GetAttributeUsage (pa);
432 type = type.BaseType;
438 public virtual MetaType GetMetaInfo ()
443 public virtual TypeSpec GetDefinition ()
448 public override string GetSignatureForDocumentation ()
450 StringBuilder sb = new StringBuilder ();
452 sb.Append (DeclaringType.GetSignatureForDocumentation ());
454 sb.Append (MemberDefinition.Namespace);
462 if (this is InflatedTypeSpec) {
464 for (int i = 0; i < Arity; ++i) {
468 sb.Append (TypeArguments[i].GetSignatureForDocumentation ());
473 sb.Append (Arity.ToString ());
477 return sb.ToString ();
480 public string GetExplicitNameSignatureForDocumentation ()
482 StringBuilder sb = new StringBuilder ();
484 sb.Append (DeclaringType.GetExplicitNameSignatureForDocumentation ());
485 } else if (MemberDefinition.Namespace != null) {
486 sb.Append (MemberDefinition.Namespace.Replace ('.', '#'));
495 for (int i = 0; i < Arity; ++i) {
499 sb.Append (TypeArguments[i].GetExplicitNameSignatureForDocumentation ());
504 return sb.ToString ();
507 public override string GetSignatureForError ()
512 s = DeclaringType.GetSignatureForError ();
513 } else if (MemberDefinition is AnonymousTypeClass) {
514 return ((AnonymousTypeClass) MemberDefinition).GetSignatureForError ();
516 s = MemberDefinition.Namespace;
519 if (!string.IsNullOrEmpty (s))
522 return s + Name + GetTypeNameSignature ();
525 public string GetSignatureForErrorIncludingAssemblyName ()
527 return string.Format ("{0} [{1}]", GetSignatureForError (), MemberDefinition.DeclaringAssembly.FullName);
530 protected virtual string GetTypeNameSignature ()
535 return "<" + TypeManager.CSharpName (MemberDefinition.TypeParameters) + ">";
538 public bool ImplementsInterface (TypeSpec iface, bool variantly)
542 var ifaces = t.Interfaces;
543 if (ifaces != null) {
544 for (int i = 0; i < ifaces.Count; ++i) {
545 if (TypeSpecComparer.IsEqual (ifaces[i], iface))
548 if (variantly && TypeSpecComparer.Variant.IsEqual (ifaces[i], iface))
553 // TODO: Why is it needed when we do it during import
560 protected virtual void InitializeMemberCache (bool onlyTypes)
563 MemberDefinition.LoadMembers (this, onlyTypes, ref cache);
564 } catch (Exception e) {
565 throw new InternalErrorException (e, "Unexpected error when loading type `{0}'", GetSignatureForError ());
569 state |= StateFlags.PendingMemberCacheMembers;
571 state &= ~StateFlags.PendingMemberCacheMembers;
575 // Is @baseClass base implementation of @type. With enabled @dynamicIsEqual the slower
576 // comparison is used to hide differences between `object' and `dynamic' for generic
577 // types. Should not be used for comparisons where G<object> != G<dynamic>
579 public static bool IsBaseClass (TypeSpec type, TypeSpec baseClass, bool dynamicIsObject)
581 if (dynamicIsObject && baseClass.IsGeneric) {
583 // Returns true for a hierarchies like this when passing baseClass of A<dynamic>
585 // class B : A<object> {}
587 type = type.BaseType;
588 while (type != null) {
589 if (TypeSpecComparer.IsEqual (type, baseClass))
592 type = type.BaseType;
598 while (type != null) {
599 type = type.BaseType;
600 if (type == baseClass)
607 public static bool IsReferenceType (TypeSpec t)
610 case MemberKind.TypeParameter:
611 return ((TypeParameterSpec) t).IsReferenceType;
612 case MemberKind.Struct:
613 case MemberKind.Enum:
614 case MemberKind.Void:
616 case MemberKind.InternalCompilerType:
618 // Null is considered to be a reference type
620 return t == InternalType.NullLiteral || t.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
626 public static bool IsValueType (TypeSpec t)
629 case MemberKind.TypeParameter:
630 return ((TypeParameterSpec) t).IsValueType;
631 case MemberKind.Struct:
632 case MemberKind.Enum:
639 public override MemberSpec InflateMember (TypeParameterInflator inflator)
641 var targs = IsGeneric ? MemberDefinition.TypeParameters : TypeSpec.EmptyTypes;
644 // When inflating nested type from inside the type instance will be same
645 // because type parameters are same for all nested types
647 if (DeclaringType == inflator.TypeInstance) {
648 return MakeGenericType (inflator.Context, targs);
651 return new InflatedTypeSpec (inflator.Context, this, inflator.TypeInstance, targs);
654 public InflatedTypeSpec MakeGenericType (IModuleContext context, TypeSpec[] targs)
656 if (targs.Length == 0 && !IsNested)
657 throw new ArgumentException ("Empty type arguments for type " + GetSignatureForError ());
659 InflatedTypeSpec instance;
661 if (inflated_instances == null) {
662 inflated_instances = new Dictionary<TypeSpec[], InflatedTypeSpec> (TypeSpecComparer.Default);
665 instance = this as InflatedTypeSpec;
666 if (instance != null) {
668 // Nested types could be inflated on already inflated instances
669 // Caching this type ensured we are using same instance for
670 // inside/outside inflation using local type parameters
672 inflated_instances.Add (TypeArguments, instance);
677 if (!inflated_instances.TryGetValue (targs, out instance)) {
678 if (GetDefinition () != this && !IsNested)
679 throw new InternalErrorException ("`{0}' must be type definition or nested non-inflated type to MakeGenericType",
680 GetSignatureForError ());
682 instance = new InflatedTypeSpec (context, this, declaringType, targs);
683 inflated_instances.Add (targs, instance);
689 public virtual TypeSpec Mutate (TypeParameterMutator mutator)
694 public override List<TypeSpec> ResolveMissingDependencies ()
696 List<TypeSpec> missing = null;
698 if (Kind == MemberKind.MissingType) {
699 missing = new List<TypeSpec> ();
704 foreach (var targ in TypeArguments) {
705 if (targ.Kind == MemberKind.MissingType) {
707 missing = new List<TypeSpec> ();
713 if (Interfaces != null) {
714 foreach (var iface in Interfaces) {
715 if (iface.Kind == MemberKind.MissingType) {
717 missing = new List<TypeSpec> ();
724 if (missing != null || BaseType == null)
727 return BaseType.ResolveMissingDependencies ();
730 public void SetMetaInfo (MetaType info)
732 if (this.info != null)
733 throw new InternalErrorException ("MetaInfo reset");
738 public void SetExtensionMethodContainer ()
740 modifiers |= Modifiers.METHOD_EXTENSION;
744 public sealed class BuiltinTypeSpec : TypeSpec
750 // Ordered carefully for fast compares
778 MulticastDelegate = 23,
791 readonly string name;
793 public BuiltinTypeSpec (MemberKind kind, string ns, string name, Type builtinKind)
794 : base (kind, null, null, null, Modifiers.PUBLIC)
796 this.type = builtinKind;
801 public BuiltinTypeSpec (string name, Type builtinKind)
802 : this (MemberKind.InternalCompilerType, "", name, builtinKind)
804 // Make all internal types CLS-compliant, non-obsolete, compact
805 state = (state & ~(StateFlags.CLSCompliant_Undetected | StateFlags.Obsolete_Undetected | StateFlags.MissingDependency_Undetected)) | StateFlags.CLSCompliant;
810 public override int Arity {
816 public override BuiltinTypeSpec.Type BuiltinType {
822 public string FullName {
824 return ns + '.' + name;
828 public override string Name {
834 public string Namespace {
842 public static bool IsPrimitiveType (TypeSpec type)
844 return type.BuiltinType >= Type.FirstPrimitive && type.BuiltinType <= Type.LastPrimitive;
847 public static bool IsPrimitiveTypeOrDecimal (TypeSpec type)
849 return type.BuiltinType >= Type.FirstPrimitive && type.BuiltinType <= Type.Decimal;
852 public override string GetSignatureForError ()
855 case "Int32": return "int";
856 case "Int64": return "long";
857 case "String": return "string";
858 case "Boolean": return "bool";
859 case "Void": return "void";
860 case "Object": return "object";
861 case "UInt32": return "uint";
862 case "Int16": return "short";
863 case "UInt16": return "ushort";
864 case "UInt64": return "ulong";
865 case "Single": return "float";
866 case "Double": return "double";
867 case "Decimal": return "decimal";
868 case "Char": return "char";
869 case "Byte": return "byte";
870 case "SByte": return "sbyte";
880 // Returns the size of type if known, otherwise, 0
882 public static int GetSize (TypeSpec type)
884 switch (type.BuiltinType) {
908 public void SetDefinition (ITypeDefinition td, MetaType type, Modifiers mod)
910 this.definition = td;
912 this.modifiers |= (mod & ~Modifiers.AccessibilityMask);
915 public void SetDefinition (TypeSpec ts)
917 this.definition = ts.MemberDefinition;
918 this.info = ts.GetMetaInfo ();
919 this.BaseType = ts.BaseType;
920 this.Interfaces = ts.Interfaces;
921 this.modifiers = ts.Modifiers;
925 static class TypeSpecComparer
928 // Does strict reference comparion only
930 public static readonly DefaultImpl Default = new DefaultImpl ();
932 public class DefaultImpl : IEqualityComparer<TypeSpec[]>
934 #region IEqualityComparer<TypeSpec[]> Members
936 bool IEqualityComparer<TypeSpec[]>.Equals (TypeSpec[] x, TypeSpec[] y)
941 if (x.Length != y.Length)
944 for (int i = 0; i < x.Length; ++i)
951 int IEqualityComparer<TypeSpec[]>.GetHashCode (TypeSpec[] obj)
954 for (int i = 0; i < obj.Length; ++i)
955 hash = (hash << 5) - hash + obj[i].GetHashCode ();
964 // When comparing type signature of overrides or overloads
965 // this version tolerates different MVARs at same position
967 public static class Override
969 public static bool IsEqual (TypeSpec a, TypeSpec b)
975 // Consider the following example:
977 // public abstract class A
979 // public abstract T Foo<T>();
982 // public class B : A
984 // public override U Foo<T>() { return default (U); }
987 // Here, `T' and `U' are method type parameters from different methods
988 // (A.Foo and B.Foo), so both `==' and Equals() will fail.
990 // However, since we're determining whether B.Foo() overrides A.Foo(),
991 // we need to do a signature based comparision and consider them equal.
994 var tp_a = a as TypeParameterSpec;
996 var tp_b = b as TypeParameterSpec;
997 return tp_b != null && tp_a.IsMethodOwned == tp_b.IsMethodOwned && tp_a.DeclaredPosition == tp_b.DeclaredPosition;
1000 var ac_a = a as ArrayContainer;
1002 var ac_b = b as ArrayContainer;
1003 return ac_b != null && ac_a.Rank == ac_b.Rank && IsEqual (ac_a.Element, ac_b.Element);
1006 if (a.BuiltinType == BuiltinTypeSpec.Type.Dynamic || b.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1007 return b.BuiltinType == BuiltinTypeSpec.Type.Object || a.BuiltinType == BuiltinTypeSpec.Type.Object;
1009 if (a.MemberDefinition != b.MemberDefinition)
1013 for (int i = 0; i < a.TypeArguments.Length; ++i) {
1014 if (!IsEqual (a.TypeArguments[i], b.TypeArguments[i]))
1018 a = a.DeclaringType;
1019 b = b.DeclaringType;
1020 } while (a != null);
1026 // Compares unordered arrays
1028 public static bool IsSame (TypeSpec[] a, TypeSpec[] b)
1033 if (a == null || b == null || a.Length != b.Length)
1036 for (int ai = 0; ai < a.Length; ++ai) {
1038 for (int bi = 0; bi < b.Length; ++bi) {
1039 if (IsEqual (a[ai], b[bi])) {
1052 public static bool IsEqual (AParametersCollection a, AParametersCollection b)
1057 if (a.Count != b.Count)
1060 for (int i = 0; i < a.Count; ++i) {
1061 if (!IsEqual (a.Types[i], b.Types[i]))
1064 if ((a.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (b.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
1073 // Type variance equality comparison
1075 public static class Variant
1077 public static bool IsEqual (TypeSpec type1, TypeSpec type2)
1079 if (!type1.IsGeneric || !type2.IsGeneric)
1082 var target_type_def = type2.MemberDefinition;
1083 if (type1.MemberDefinition != target_type_def)
1086 var t1_targs = type1.TypeArguments;
1087 var t2_targs = type2.TypeArguments;
1088 var targs_definition = target_type_def.TypeParameters;
1090 if (!type1.IsInterface && !type1.IsDelegate) {
1094 for (int i = 0; i < targs_definition.Length; ++i) {
1095 if (TypeSpecComparer.IsEqual (t1_targs[i], t2_targs[i]))
1098 Variance v = targs_definition[i].Variance;
1099 if (v == Variance.None) {
1103 if (v == Variance.Covariant) {
1104 if (!Convert.ImplicitReferenceConversionExists (t1_targs[i], t2_targs[i]))
1106 } else if (!Convert.ImplicitReferenceConversionExists (t2_targs[i], t1_targs[i])) {
1116 // Checks whether two generic instances may become equal for some
1117 // particular instantiation (26.3.1).
1119 public static class Unify
1122 // Either @a or @b must be generic type
1124 public static bool IsEqual (TypeSpec a, TypeSpec b)
1126 if (a.MemberDefinition != b.MemberDefinition) {
1127 var base_ifaces = a.Interfaces;
1128 if (base_ifaces != null) {
1129 foreach (var base_iface in base_ifaces) {
1130 if (base_iface.Arity > 0 && IsEqual (base_iface, b))
1138 var ta = a.TypeArguments;
1139 var tb = b.TypeArguments;
1140 for (int i = 0; i < ta.Length; i++) {
1141 if (!MayBecomeEqualGenericTypes (ta[i], tb[i]))
1148 static bool ContainsTypeParameter (TypeSpec tparam, TypeSpec type)
1150 TypeSpec[] targs = type.TypeArguments;
1151 for (int i = 0; i < targs.Length; i++) {
1152 if (tparam == targs[i])
1155 if (ContainsTypeParameter (tparam, targs[i]))
1163 /// Check whether `a' and `b' may become equal generic types.
1164 /// The algorithm to do that is a little bit complicated.
1166 static bool MayBecomeEqualGenericTypes (TypeSpec a, TypeSpec b)
1168 if (a.IsGenericParameter) {
1170 // If a is an array of a's type, they may never
1177 // If b is a generic parameter or an actual type,
1178 // they may become equal:
1180 // class X<T,U> : I<T>, I<U>
1181 // class X<T> : I<T>, I<float>
1183 if (b.IsGenericParameter)
1184 return a != b && a.DeclaringType == b.DeclaringType;
1187 // We're now comparing a type parameter with a
1188 // generic instance. They may become equal unless
1189 // the type parameter appears anywhere in the
1190 // generic instance:
1192 // class X<T,U> : I<T>, I<X<U>>
1193 // -> error because you could instanciate it as
1196 // class X<T> : I<T>, I<X<T>> -> ok
1199 return !ContainsTypeParameter (a, b);
1202 if (b.IsGenericParameter)
1203 return MayBecomeEqualGenericTypes (b, a);
1206 // At this point, neither a nor b are a type parameter.
1208 // If one of them is a generic instance, compare them (if the
1209 // other one is not a generic instance, they can never
1212 if (TypeManager.IsGenericType (a) || TypeManager.IsGenericType (b))
1213 return IsEqual (a, b);
1216 // If both of them are arrays.
1218 var a_ac = a as ArrayContainer;
1220 var b_ac = b as ArrayContainer;
1221 if (b_ac == null || a_ac.Rank != b_ac.Rank)
1224 return MayBecomeEqualGenericTypes (a_ac.Element, b_ac.Element);
1228 // Ok, two ordinary types.
1234 public static bool Equals (TypeSpec[] x, TypeSpec[] y)
1239 if (x.Length != y.Length)
1242 for (int i = 0; i < x.Length; ++i)
1243 if (!IsEqual (x[i], y[i]))
1250 // Identity type conversion
1252 // Default reference comparison, it has to be used when comparing
1253 // two possible dynamic/internal types
1255 public static bool IsEqual (TypeSpec a, TypeSpec b)
1258 // This also rejects dynamic == dynamic
1259 return a.Kind != MemberKind.InternalCompilerType || a.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
1262 if (a == null || b == null)
1266 var a_a = (ArrayContainer) a;
1267 var b_a = b as ArrayContainer;
1271 return a_a.Rank == b_a.Rank && IsEqual (a_a.Element, b_a.Element);
1274 if (!a.IsGeneric || !b.IsGeneric) {
1276 // object and dynamic are considered equivalent there is an identity conversion
1277 // between object and dynamic, and between constructed types that are the same
1278 // when replacing all occurences of dynamic with object.
1280 if (a.BuiltinType == BuiltinTypeSpec.Type.Dynamic || b.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1281 return b.BuiltinType == BuiltinTypeSpec.Type.Object || a.BuiltinType == BuiltinTypeSpec.Type.Object;
1286 if (a.MemberDefinition != b.MemberDefinition)
1290 if (!Equals (a.TypeArguments, b.TypeArguments))
1293 a = a.DeclaringType;
1294 b = b.DeclaringType;
1295 } while (a != null);
1301 public interface ITypeDefinition : IMemberDefinition
1303 IAssemblyDefinition DeclaringAssembly { get; }
1304 string Namespace { get; }
1305 bool IsPartial { get; }
1306 int TypeParametersCount { get; }
1307 TypeParameterSpec[] TypeParameters { get; }
1309 TypeSpec GetAttributeCoClass ();
1310 string GetAttributeDefaultMember ();
1311 AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa);
1312 bool IsInternalAsPublic (IAssemblyDefinition assembly);
1313 void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache);
1316 class InternalType : TypeSpec, ITypeDefinition
1318 public static readonly InternalType AnonymousMethod = new InternalType ("anonymous method");
1319 public static readonly InternalType Arglist = new InternalType ("__arglist");
1320 public static readonly InternalType MethodGroup = new InternalType ("method group");
1321 public static readonly InternalType NullLiteral = new InternalType ("null");
1322 public static readonly InternalType FakeInternalType = new InternalType ("<fake$type>");
1323 public static readonly InternalType Namespace = new InternalType ("<namespace>");
1324 public static readonly InternalType ErrorType = new InternalType ("<error>");
1326 readonly string name;
1328 InternalType (string name)
1329 : base (MemberKind.InternalCompilerType, null, null, null, Modifiers.PUBLIC)
1332 this.definition = this;
1333 cache = MemberCache.Empty;
1335 // Make all internal types CLS-compliant, non-obsolete
1336 state = (state & ~(StateFlags.CLSCompliant_Undetected | StateFlags.Obsolete_Undetected)) | StateFlags.CLSCompliant;
1341 public override int Arity {
1347 IAssemblyDefinition ITypeDefinition.DeclaringAssembly {
1349 throw new NotImplementedException ();
1353 bool IMemberDefinition.IsImported {
1359 bool ITypeDefinition.IsPartial {
1365 public override string Name {
1371 string ITypeDefinition.Namespace {
1377 int ITypeDefinition.TypeParametersCount {
1383 TypeParameterSpec[] ITypeDefinition.TypeParameters {
1391 public override string GetSignatureForError ()
1396 #region ITypeDefinition Members
1398 TypeSpec ITypeDefinition.GetAttributeCoClass ()
1403 string ITypeDefinition.GetAttributeDefaultMember ()
1408 AttributeUsageAttribute ITypeDefinition.GetAttributeUsage (PredefinedAttribute pa)
1413 bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly)
1415 throw new NotImplementedException ();
1418 void ITypeDefinition.LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
1420 throw new NotImplementedException ();
1423 string[] IMemberDefinition.ConditionalConditions ()
1428 ObsoleteAttribute IMemberDefinition.GetAttributeObsolete ()
1433 bool? IMemberDefinition.CLSAttributeValue {
1439 void IMemberDefinition.SetIsAssigned ()
1443 void IMemberDefinition.SetIsUsed ()
1450 public abstract class ElementTypeSpec : TypeSpec, ITypeDefinition
1452 protected ElementTypeSpec (MemberKind kind, TypeSpec element, MetaType info)
1453 : base (kind, element.DeclaringType, null, info, element.Modifiers)
1455 this.Element = element;
1457 // Some flags can be copied directly from the element
1458 const StateFlags shared_flags = StateFlags.CLSCompliant | StateFlags.CLSCompliant_Undetected
1459 | StateFlags.Obsolete | StateFlags.Obsolete_Undetected | StateFlags.HasDynamicElement;
1460 state &= ~shared_flags;
1461 state |= (element.state & shared_flags);
1463 if (element.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1464 state |= StateFlags.HasDynamicElement;
1466 // Has to use its own type definition instead of just element definition to
1467 // correctly identify itself for cases like x.MemberDefininition == predefined.MemberDefinition
1468 this.definition = this;
1470 cache = MemberCache.Empty;
1475 public TypeSpec Element { get; private set; }
1477 bool ITypeDefinition.IsPartial {
1483 public override string Name {
1485 throw new NotSupportedException ();
1491 public override ObsoleteAttribute GetAttributeObsolete ()
1493 return Element.GetAttributeObsolete ();
1496 protected virtual string GetPostfixSignature ()
1501 public override string GetSignatureForDocumentation ()
1503 return Element.GetSignatureForDocumentation () + GetPostfixSignature ();
1506 public override string GetSignatureForError ()
1508 return Element.GetSignatureForError () + GetPostfixSignature ();
1511 public override TypeSpec Mutate (TypeParameterMutator mutator)
1513 var me = Element.Mutate (mutator);
1517 var mutated = (ElementTypeSpec) MemberwiseClone ();
1518 mutated.Element = me;
1519 mutated.info = null;
1523 #region ITypeDefinition Members
1525 IAssemblyDefinition ITypeDefinition.DeclaringAssembly {
1527 return Element.MemberDefinition.DeclaringAssembly;
1531 bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly)
1533 return Element.MemberDefinition.IsInternalAsPublic (assembly);
1536 public string Namespace {
1537 get { throw new NotImplementedException (); }
1540 public int TypeParametersCount {
1546 public TypeParameterSpec[] TypeParameters {
1548 throw new NotSupportedException ();
1552 public TypeSpec GetAttributeCoClass ()
1554 return Element.MemberDefinition.GetAttributeCoClass ();
1557 public string GetAttributeDefaultMember ()
1559 return Element.MemberDefinition.GetAttributeDefaultMember ();
1562 public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
1564 Element.MemberDefinition.LoadMembers (declaringType, onlyTypes, ref cache);
1567 public bool IsImported {
1569 return Element.MemberDefinition.IsImported;
1573 public string[] ConditionalConditions ()
1575 return Element.MemberDefinition.ConditionalConditions ();
1578 bool? IMemberDefinition.CLSAttributeValue {
1580 return Element.MemberDefinition.CLSAttributeValue;
1584 public void SetIsAssigned ()
1586 Element.MemberDefinition.SetIsAssigned ();
1589 public void SetIsUsed ()
1591 Element.MemberDefinition.SetIsUsed ();
1597 public class ArrayContainer : ElementTypeSpec
1599 public struct TypeRankPair : IEquatable<TypeRankPair>
1604 public TypeRankPair (TypeSpec ts, int rank)
1610 public override int GetHashCode ()
1612 return ts.GetHashCode () ^ rank.GetHashCode ();
1615 #region IEquatable<Tuple<T1,T2>> Members
1617 public bool Equals (TypeRankPair other)
1619 return other.ts == ts && other.rank == rank;
1626 readonly ModuleContainer module;
1628 private ArrayContainer (ModuleContainer module, TypeSpec element, int rank)
1629 : base (MemberKind.ArrayType, element, null)
1631 this.module = module;
1641 public MethodInfo GetConstructor ()
1643 var mb = module.Builder;
1645 var arg_types = new MetaType[rank];
1646 for (int i = 0; i < rank; i++)
1647 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1649 var ctor = mb.GetArrayMethod (
1650 GetMetaInfo (), Constructor.ConstructorName,
1651 CallingConventions.HasThis,
1657 public MethodInfo GetAddressMethod ()
1659 var mb = module.Builder;
1661 var arg_types = new MetaType[rank];
1662 for (int i = 0; i < rank; i++)
1663 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1665 var address = mb.GetArrayMethod (
1666 GetMetaInfo (), "Address",
1667 CallingConventions.HasThis | CallingConventions.Standard,
1668 ReferenceContainer.MakeType (module, Element).GetMetaInfo (), arg_types);
1673 public MethodInfo GetGetMethod ()
1675 var mb = module.Builder;
1677 var arg_types = new MetaType[rank];
1678 for (int i = 0; i < rank; i++)
1679 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1681 var get = mb.GetArrayMethod (
1682 GetMetaInfo (), "Get",
1683 CallingConventions.HasThis | CallingConventions.Standard,
1684 Element.GetMetaInfo (), arg_types);
1689 public MethodInfo GetSetMethod ()
1691 var mb = module.Builder;
1693 var arg_types = new MetaType[rank + 1];
1694 for (int i = 0; i < rank; i++)
1695 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1697 arg_types[rank] = Element.GetMetaInfo ();
1699 var set = mb.GetArrayMethod (
1700 GetMetaInfo (), "Set",
1701 CallingConventions.HasThis | CallingConventions.Standard,
1702 module.Compiler.BuiltinTypes.Void.GetMetaInfo (), arg_types);
1707 public override MetaType GetMetaInfo ()
1711 info = Element.GetMetaInfo ().MakeArrayType ();
1713 info = Element.GetMetaInfo ().MakeArrayType (rank);
1719 protected override string GetPostfixSignature()
1721 return GetPostfixSignature (rank);
1724 public static string GetPostfixSignature (int rank)
1726 StringBuilder sb = new StringBuilder ();
1728 for (int i = 1; i < rank; i++) {
1733 return sb.ToString ();
1736 public override string GetSignatureForDocumentation ()
1738 StringBuilder sb = new StringBuilder ();
1739 GetElementSignatureForDocumentation (sb);
1740 return sb.ToString ();
1743 void GetElementSignatureForDocumentation (StringBuilder sb)
1745 var ac = Element as ArrayContainer;
1747 sb.Append (Element.GetSignatureForDocumentation ());
1749 ac.GetElementSignatureForDocumentation (sb);
1752 for (int i = 1; i < rank; i++) {
1761 public static ArrayContainer MakeType (ModuleContainer module, TypeSpec element)
1763 return MakeType (module, element, 1);
1766 public static ArrayContainer MakeType (ModuleContainer module, TypeSpec element, int rank)
1769 var key = new TypeRankPair (element, rank);
1770 if (!module.ArrayTypesCache.TryGetValue (key, out ac)) {
1771 ac = new ArrayContainer (module, element, rank) {
1772 BaseType = module.Compiler.BuiltinTypes.Array
1775 module.ArrayTypesCache.Add (key, ac);
1782 class ReferenceContainer : ElementTypeSpec
1784 private ReferenceContainer (TypeSpec element)
1785 : base (MemberKind.Class, element, null) // TODO: Kind.Class is most likely wrong
1789 public override MetaType GetMetaInfo ()
1792 info = Element.GetMetaInfo ().MakeByRefType ();
1798 public static ReferenceContainer MakeType (ModuleContainer module, TypeSpec element)
1800 ReferenceContainer pc;
1801 if (!module.ReferenceTypesCache.TryGetValue (element, out pc)) {
1802 pc = new ReferenceContainer (element);
1803 module.ReferenceTypesCache.Add (element, pc);
1810 class PointerContainer : ElementTypeSpec
1812 private PointerContainer (TypeSpec element)
1813 : base (MemberKind.PointerType, element, null)
1815 // It's never CLS-Compliant
1816 state &= ~StateFlags.CLSCompliant_Undetected;
1819 public override MetaType GetMetaInfo ()
1822 info = Element.GetMetaInfo ().MakePointerType ();
1828 protected override string GetPostfixSignature()
1833 public static PointerContainer MakeType (ModuleContainer module, TypeSpec element)
1835 PointerContainer pc;
1836 if (!module.PointerTypesCache.TryGetValue (element, out pc)) {
1837 pc = new PointerContainer (element);
1838 module.PointerTypesCache.Add (element, pc);