2
// typespec.cs: Type specification
4
// Authors: Marek Safar (marek.safar@gmail.com)
6
// Dual licensed under the terms of the MIT X11 or GNU GPL
8
// Copyright 2010 Novell, Inc
9
// Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
13
using System.Collections.Generic;
18
using MetaType = IKVM.Reflection.Type;
19
using IKVM.Reflection;
21
using MetaType = System.Type;
22
using System.Reflection;
28
// Inflated or non-inflated representation of any type.
30
public class TypeSpec : MemberSpec
32
protected MetaType info;
33
protected MemberCache cache;
34
protected IList<TypeSpec> ifaces;
37
Dictionary<TypeSpec[], InflatedTypeSpec> inflated_instances;
39
public static readonly TypeSpec[] EmptyTypes = new TypeSpec[0];
42
// Reflection Emit hacking
43
static readonly Type TypeBuilder;
44
static readonly Type GenericTypeBuilder;
48
var assembly = typeof (object).Assembly;
49
TypeBuilder = assembly.GetType ("System.Reflection.Emit.TypeBuilder");
50
GenericTypeBuilder = assembly.GetType ("System.Reflection.MonoGenericClass");
51
if (GenericTypeBuilder == null)
52
GenericTypeBuilder = assembly.GetType ("System.Reflection.Emit.TypeBuilderInstantiation");
56
public TypeSpec (MemberKind kind, TypeSpec declaringType, ITypeDefinition definition, MetaType info, Modifiers modifiers)
57
: base (kind, declaringType, definition, modifiers)
59
this.declaringType = declaringType;
62
if (definition != null && definition.TypeParametersCount > 0)
63
state |= StateFlags.IsGeneric;
68
public override int Arity {
70
return MemberDefinition.TypeParametersCount;
74
public virtual TypeSpec BaseType {
83
public virtual BuiltinTypeSpec.Type BuiltinType {
85
return BuiltinTypeSpec.Type.None;
89
public bool HasDynamicElement {
91
return (state & StateFlags.HasDynamicElement) != 0;
96
// Returns a list of all interfaces including
97
// interfaces from base type or base interfaces
99
public virtual IList<TypeSpec> Interfaces {
101
if ((state & StateFlags.InterfacesImported) == 0) {
102
state |= StateFlags.InterfacesImported;
105
// Delay interfaces expansion to save memory and once all
106
// base types has been imported to avoid problems where
107
// interface references type before its base was imported
109
var imported = MemberDefinition as ImportedTypeDefinition;
110
if (imported != null && Kind != MemberKind.MissingType)
111
imported.DefineInterfaces (this);
122
public bool IsArray {
124
return Kind == MemberKind.ArrayType;
128
public bool IsAttribute {
135
if (type.BuiltinType == BuiltinTypeSpec.Type.Attribute)
141
type = type.base_type;
142
} while (type != null);
148
public bool IsInterface {
150
return Kind == MemberKind.Interface;
154
public bool IsClass {
156
return Kind == MemberKind.Class;
160
public bool IsConstantCompatible {
162
if ((Kind & (MemberKind.Enum | MemberKind.Class | MemberKind.Interface | MemberKind.Delegate | MemberKind.ArrayType)) != 0)
165
switch (BuiltinType) {
166
case BuiltinTypeSpec.Type.Int:
167
case BuiltinTypeSpec.Type.UInt:
168
case BuiltinTypeSpec.Type.Long:
169
case BuiltinTypeSpec.Type.ULong:
170
case BuiltinTypeSpec.Type.Float:
171
case BuiltinTypeSpec.Type.Double:
172
case BuiltinTypeSpec.Type.Char:
173
case BuiltinTypeSpec.Type.Short:
174
case BuiltinTypeSpec.Type.Decimal:
175
case BuiltinTypeSpec.Type.Bool:
176
case BuiltinTypeSpec.Type.SByte:
177
case BuiltinTypeSpec.Type.Byte:
178
case BuiltinTypeSpec.Type.UShort:
179
case BuiltinTypeSpec.Type.Dynamic:
187
public bool IsDelegate {
189
return Kind == MemberKind.Delegate;
194
// Returns true for instances of Expression<T>
196
public virtual bool IsExpressionTreeType {
201
state = value ? state | StateFlags.InflatedExpressionType : state & ~StateFlags.InflatedExpressionType;
207
return Kind == MemberKind.Enum;
212
// Returns true for instances of IList<T>, IEnumerable<T>, ICollection<T>
214
public virtual bool IsGenericIterateInterface {
219
state = value ? state | StateFlags.GenericIterateInterface : state & ~StateFlags.GenericIterateInterface;
224
// Returns true for instances of System.Threading.Tasks.Task<T>
226
public virtual bool IsGenericTask {
231
state = value ? state | StateFlags.GenericTask : state & ~StateFlags.GenericTask;
235
// TODO: Should probably do
236
// IsGenericType -- recursive
237
// HasTypeParameter -- non-recursive
238
public bool IsGenericOrParentIsGeneric {
244
ts = ts.declaringType;
245
} while (ts != null);
251
public bool IsGenericParameter {
253
return Kind == MemberKind.TypeParameter;
258
// Returns true for instances of Nullable<T>
260
public virtual bool IsNullableType {
265
state = value ? state | StateFlags.InflatedNullableType : state & ~StateFlags.InflatedNullableType;
269
public bool IsNested {
270
get { return declaringType != null && Kind != MemberKind.TypeParameter; }
273
public bool IsPointer {
275
return Kind == MemberKind.PointerType;
279
public bool IsSealed {
280
get { return (Modifiers & Modifiers.SEALED) != 0; }
283
public bool IsSpecialRuntimeType {
285
return (state & StateFlags.SpecialRuntimeType) != 0;
288
state = value ? state | StateFlags.SpecialRuntimeType : state & ~StateFlags.SpecialRuntimeType;
292
public bool IsStruct {
294
return Kind == MemberKind.Struct;
298
public bool IsTypeBuilder {
303
var meta = GetMetaInfo().GetType ();
304
return meta == TypeBuilder || meta == GenericTypeBuilder;
310
// Whether a type is unmanaged. This is used by the unsafe code
312
public bool IsUnmanaged {
315
return ((ElementTypeSpec) this).Element.IsUnmanaged;
317
var ds = MemberDefinition as TypeDefinition;
319
return ds.IsUnmanagedType ();
321
if (Kind == MemberKind.Void)
324
if (IsNested && DeclaringType.IsGenericOrParentIsGeneric)
327
return IsValueType (this);
332
// A cache of all type members (including nested types)
334
public MemberCache MemberCache {
336
if (cache == null || (state & StateFlags.PendingMemberCacheMembers) != 0)
337
InitializeMemberCache (false);
343
throw new InternalErrorException ("Membercache reset");
349
public MemberCache MemberCacheTypes {
352
InitializeMemberCache (true);
358
public new ITypeDefinition MemberDefinition {
360
return (ITypeDefinition) definition;
364
// TODO: Wouldn't be better to rely on cast to InflatedTypeSpec and
365
// remove the property, YES IT WOULD !!!
366
public virtual TypeSpec[] TypeArguments {
367
get { return TypeSpec.EmptyTypes; }
372
public virtual bool AddInterface (TypeSpec iface)
374
if ((state & StateFlags.InterfacesExpanded) != 0)
375
throw new InternalErrorException ("Modifying expanded interface list");
377
if (ifaces == null) {
378
ifaces = new List<TypeSpec> () { iface };
382
if (!ifaces.Contains (iface)) {
391
// Special version used during type definition
393
public bool AddInterfaceDefined (TypeSpec iface)
395
if (!AddInterface (iface))
399
// We can get into a situation where a type is inflated before
400
// its interfaces are resoved. Consider this situation
402
// class A<T> : X<A<int>>, IFoo {}
404
// When resolving base class of X`1 we inflate context type A`1
405
// All this happens before we even hit IFoo resolve. Without
406
// additional expansion any inside usage of A<T> would miss IFoo
407
// interface because it comes from early inflated A`1 definition.
409
if (inflated_instances != null) {
411
// Inflate only existing instances not any new instances added
412
// during AddInterface
414
var inflated_existing = inflated_instances.Values.ToArray ();
415
foreach (var inflated in inflated_existing) {
416
inflated.AddInterface (iface);
424
// Returns all type arguments, usefull for nested types
426
public static TypeSpec[] GetAllTypeArguments (TypeSpec type)
428
IList<TypeSpec> targs = TypeSpec.EmptyTypes;
431
if (type.Arity > 0) {
432
if (targs.Count == 0) {
433
targs = type.TypeArguments;
435
var list = targs as List<TypeSpec> ?? new List<TypeSpec> (targs);
436
list.AddRange (type.TypeArguments);
441
type = type.declaringType;
442
} while (type != null);
444
return targs as TypeSpec[] ?? ((List<TypeSpec>) targs).ToArray ();
447
public AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa)
449
if (Kind != MemberKind.Class)
450
throw new InternalErrorException ();
453
return Attribute.DefaultUsageAttribute;
455
AttributeUsageAttribute aua = null;
457
while (type != null) {
458
aua = type.MemberDefinition.GetAttributeUsage (pa);
462
type = type.BaseType;
469
// Return metadata information used during emit to describe the type
471
public virtual MetaType GetMetaInfo ()
476
public virtual TypeSpec GetDefinition ()
482
// Text representation of type used by documentation writer
484
public override string GetSignatureForDocumentation ()
486
StringBuilder sb = new StringBuilder ();
488
sb.Append (DeclaringType.GetSignatureForDocumentation ());
490
sb.Append (MemberDefinition.Namespace);
498
if (this is InflatedTypeSpec) {
500
for (int i = 0; i < Arity; ++i) {
504
sb.Append (TypeArguments[i].GetSignatureForDocumentation ());
509
sb.Append (Arity.ToString ());
513
return sb.ToString ();
516
public string GetExplicitNameSignatureForDocumentation ()
518
StringBuilder sb = new StringBuilder ();
520
sb.Append (DeclaringType.GetExplicitNameSignatureForDocumentation ());
521
} else if (MemberDefinition.Namespace != null) {
522
sb.Append (MemberDefinition.Namespace.Replace ('.', '#'));
531
for (int i = 0; i < Arity; ++i) {
535
sb.Append (TypeArguments[i].GetExplicitNameSignatureForDocumentation ());
540
return sb.ToString ();
543
public override string GetSignatureForError ()
548
s = DeclaringType.GetSignatureForError ();
549
} else if (MemberDefinition is AnonymousTypeClass) {
550
return ((AnonymousTypeClass) MemberDefinition).GetSignatureForError ();
552
s = MemberDefinition.Namespace;
555
if (!string.IsNullOrEmpty (s))
558
return s + Name + GetTypeNameSignature ();
561
public string GetSignatureForErrorIncludingAssemblyName ()
563
return string.Format ("{0} [{1}]", GetSignatureForError (), MemberDefinition.DeclaringAssembly.FullName);
566
protected virtual string GetTypeNameSignature ()
571
return "<" + TypeManager.CSharpName (MemberDefinition.TypeParameters) + ">";
574
public bool ImplementsInterface (TypeSpec iface, bool variantly)
576
var ifaces = Interfaces;
577
if (ifaces != null) {
578
for (int i = 0; i < ifaces.Count; ++i) {
579
if (TypeSpecComparer.IsEqual (ifaces[i], iface))
582
if (variantly && TypeSpecComparer.Variant.IsEqual (ifaces[i], iface))
590
protected virtual void InitializeMemberCache (bool onlyTypes)
593
MemberDefinition.LoadMembers (this, onlyTypes, ref cache);
594
} catch (Exception e) {
595
throw new InternalErrorException (e, "Unexpected error when loading type `{0}'", GetSignatureForError ());
599
state |= StateFlags.PendingMemberCacheMembers;
601
state &= ~StateFlags.PendingMemberCacheMembers;
605
// Is @baseClass base implementation of @type. With enabled @dynamicIsEqual the slower
606
// comparison is used to hide differences between `object' and `dynamic' for generic
607
// types. Should not be used for comparisons where G<object> != G<dynamic>
609
public static bool IsBaseClass (TypeSpec type, TypeSpec baseClass, bool dynamicIsObject)
611
if (dynamicIsObject && baseClass.IsGeneric) {
613
// Returns true for a hierarchies like this when passing baseClass of A<dynamic>
615
// class B : A<object> {}
617
type = type.BaseType;
618
while (type != null) {
619
if (TypeSpecComparer.IsEqual (type, baseClass))
622
type = type.BaseType;
628
while (type != null) {
629
type = type.BaseType;
630
if (type == baseClass)
637
public static bool IsReferenceType (TypeSpec t)
640
case MemberKind.TypeParameter:
641
return ((TypeParameterSpec) t).IsReferenceType;
642
case MemberKind.Struct:
643
case MemberKind.Enum:
644
case MemberKind.Void:
646
case MemberKind.InternalCompilerType:
648
// Null is considered to be a reference type
650
return t == InternalType.NullLiteral || t.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
656
public static bool IsValueType (TypeSpec t)
659
case MemberKind.TypeParameter:
660
return ((TypeParameterSpec) t).IsValueType;
661
case MemberKind.Struct:
662
case MemberKind.Enum:
669
public override MemberSpec InflateMember (TypeParameterInflator inflator)
671
var targs = IsGeneric ? MemberDefinition.TypeParameters : TypeSpec.EmptyTypes;
674
// When inflating nested type from inside the type instance will be same
675
// because type parameters are same for all nested types
677
if (DeclaringType == inflator.TypeInstance) {
678
return MakeGenericType (inflator.Context, targs);
681
return new InflatedTypeSpec (inflator.Context, this, inflator.TypeInstance, targs);
685
// Inflates current type using specific type arguments
687
public InflatedTypeSpec MakeGenericType (IModuleContext context, TypeSpec[] targs)
689
if (targs.Length == 0 && !IsNested)
690
throw new ArgumentException ("Empty type arguments for type " + GetSignatureForError ());
692
InflatedTypeSpec instance;
694
if (inflated_instances == null) {
695
inflated_instances = new Dictionary<TypeSpec[], InflatedTypeSpec> (TypeSpecComparer.Default);
698
instance = this as InflatedTypeSpec;
699
if (instance != null) {
701
// Nested types could be inflated on already inflated instances
702
// Caching this type ensured we are using same instance for
703
// inside/outside inflation using local type parameters
705
inflated_instances.Add (TypeArguments, instance);
710
if (!inflated_instances.TryGetValue (targs, out instance)) {
711
if (GetDefinition () != this && !IsNested)
712
throw new InternalErrorException ("`{0}' must be type definition or nested non-inflated type to MakeGenericType",
713
GetSignatureForError ());
715
instance = new InflatedTypeSpec (context, this, declaringType, targs);
716
inflated_instances.Add (targs, instance);
722
public virtual TypeSpec Mutate (TypeParameterMutator mutator)
727
public override List<TypeSpec> ResolveMissingDependencies ()
729
List<TypeSpec> missing = null;
731
if (Kind == MemberKind.MissingType) {
732
missing = new List<TypeSpec> ();
737
foreach (var targ in TypeArguments) {
738
if (targ.Kind == MemberKind.MissingType) {
740
missing = new List<TypeSpec> ();
746
if (Interfaces != null) {
747
foreach (var iface in Interfaces) {
748
if (iface.Kind == MemberKind.MissingType) {
750
missing = new List<TypeSpec> ();
757
if (MemberDefinition.TypeParametersCount > 0) {
758
foreach (var tp in MemberDefinition.TypeParameters) {
759
var tp_missing = tp.GetMissingDependencies ();
760
if (tp_missing != null) {
762
missing = new List<TypeSpec> ();
764
missing.AddRange (tp_missing);
769
if (missing != null || BaseType == null)
772
return BaseType.ResolveMissingDependencies ();
775
public void SetMetaInfo (MetaType info)
777
if (this.info != null)
778
throw new InternalErrorException ("MetaInfo reset");
783
public void SetExtensionMethodContainer ()
785
modifiers |= Modifiers.METHOD_EXTENSION;
790
// Special version used for types which must exist in corlib or
791
// the compiler cannot work
793
public sealed class BuiltinTypeSpec : TypeSpec
799
// Ordered carefully for fast compares
827
MulticastDelegate = 23,
840
readonly string name;
842
public BuiltinTypeSpec (MemberKind kind, string ns, string name, Type builtinKind)
843
: base (kind, null, null, null, Modifiers.PUBLIC)
845
this.type = builtinKind;
850
public BuiltinTypeSpec (string name, Type builtinKind)
851
: this (MemberKind.InternalCompilerType, "", name, builtinKind)
853
// Make all internal types CLS-compliant, non-obsolete, compact
854
state = (state & ~(StateFlags.CLSCompliant_Undetected | StateFlags.Obsolete_Undetected | StateFlags.MissingDependency_Undetected)) | StateFlags.CLSCompliant;
859
public override int Arity {
865
public override BuiltinTypeSpec.Type BuiltinType {
871
public string FullName {
873
return ns + '.' + name;
877
public override string Name {
883
public string Namespace {
891
public static bool IsPrimitiveType (TypeSpec type)
893
return type.BuiltinType >= Type.FirstPrimitive && type.BuiltinType <= Type.LastPrimitive;
896
public static bool IsPrimitiveTypeOrDecimal (TypeSpec type)
898
return type.BuiltinType >= Type.FirstPrimitive && type.BuiltinType <= Type.Decimal;
901
public override string GetSignatureForError ()
904
case "Int32": return "int";
905
case "Int64": return "long";
906
case "String": return "string";
907
case "Boolean": return "bool";
908
case "Void": return "void";
909
case "Object": return "object";
910
case "UInt32": return "uint";
911
case "Int16": return "short";
912
case "UInt16": return "ushort";
913
case "UInt64": return "ulong";
914
case "Single": return "float";
915
case "Double": return "double";
916
case "Decimal": return "decimal";
917
case "Char": return "char";
918
case "Byte": return "byte";
919
case "SByte": return "sbyte";
929
// Returns the size of type if known, otherwise, 0
931
public static int GetSize (TypeSpec type)
933
switch (type.BuiltinType) {
957
public void SetDefinition (ITypeDefinition td, MetaType type, Modifiers mod)
959
this.definition = td;
961
this.modifiers |= (mod & ~Modifiers.AccessibilityMask);
964
public void SetDefinition (TypeSpec ts)
966
this.definition = ts.MemberDefinition;
967
this.info = ts.GetMetaInfo ();
968
this.BaseType = ts.BaseType;
969
this.Interfaces = ts.Interfaces;
970
this.modifiers = ts.Modifiers;
975
// Various type comparers used by compiler
977
static class TypeSpecComparer
980
// Does strict reference comparion only
982
public static readonly DefaultImpl Default = new DefaultImpl ();
984
public class DefaultImpl : IEqualityComparer<TypeSpec[]>
986
#region IEqualityComparer<TypeSpec[]> Members
988
bool IEqualityComparer<TypeSpec[]>.Equals (TypeSpec[] x, TypeSpec[] y)
993
if (x.Length != y.Length)
996
for (int i = 0; i < x.Length; ++i)
1003
int IEqualityComparer<TypeSpec[]>.GetHashCode (TypeSpec[] obj)
1006
for (int i = 0; i < obj.Length; ++i)
1007
hash = (hash << 5) - hash + obj[i].GetHashCode ();
1016
// When comparing type signature of overrides or overloads
1017
// this version tolerates different MVARs at same position
1019
public static class Override
1021
public static bool IsEqual (TypeSpec a, TypeSpec b)
1027
// Consider the following example:
1029
// public abstract class A
1031
// public abstract T Foo<T>();
1034
// public class B : A
1036
// public override U Foo<T>() { return default (U); }
1039
// Here, `T' and `U' are method type parameters from different methods
1040
// (A.Foo and B.Foo), so both `==' and Equals() will fail.
1042
// However, since we're determining whether B.Foo() overrides A.Foo(),
1043
// we need to do a signature based comparision and consider them equal.
1046
var tp_a = a as TypeParameterSpec;
1048
var tp_b = b as TypeParameterSpec;
1049
return tp_b != null && tp_a.IsMethodOwned == tp_b.IsMethodOwned && tp_a.DeclaredPosition == tp_b.DeclaredPosition;
1052
var ac_a = a as ArrayContainer;
1054
var ac_b = b as ArrayContainer;
1055
return ac_b != null && ac_a.Rank == ac_b.Rank && IsEqual (ac_a.Element, ac_b.Element);
1058
if (a.BuiltinType == BuiltinTypeSpec.Type.Dynamic || b.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1059
return b.BuiltinType == BuiltinTypeSpec.Type.Object || a.BuiltinType == BuiltinTypeSpec.Type.Object;
1061
if (a.MemberDefinition != b.MemberDefinition)
1065
for (int i = 0; i < a.TypeArguments.Length; ++i) {
1066
if (!IsEqual (a.TypeArguments[i], b.TypeArguments[i]))
1070
a = a.DeclaringType;
1071
b = b.DeclaringType;
1072
} while (a != null);
1077
public static bool IsEqual (TypeSpec[] a, TypeSpec[] b)
1082
if (a.Length != b.Length)
1085
for (int i = 0; i < a.Length; ++i) {
1086
if (!IsEqual (a[i], b[i]))
1095
// Compares unordered arrays
1097
public static bool IsSame (TypeSpec[] a, TypeSpec[] b)
1102
if (a == null || b == null || a.Length != b.Length)
1105
for (int ai = 0; ai < a.Length; ++ai) {
1107
for (int bi = 0; bi < b.Length; ++bi) {
1108
if (IsEqual (a[ai], b[bi])) {
1121
public static bool IsEqual (AParametersCollection a, AParametersCollection b)
1126
if (a.Count != b.Count)
1129
for (int i = 0; i < a.Count; ++i) {
1130
if (!IsEqual (a.Types[i], b.Types[i]))
1133
if ((a.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (b.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
1142
// Type variance equality comparison
1144
public static class Variant
1146
public static bool IsEqual (TypeSpec type1, TypeSpec type2)
1148
if (!type1.IsGeneric || !type2.IsGeneric)
1151
var target_type_def = type2.MemberDefinition;
1152
if (type1.MemberDefinition != target_type_def)
1155
var t1_targs = type1.TypeArguments;
1156
var t2_targs = type2.TypeArguments;
1157
var targs_definition = target_type_def.TypeParameters;
1159
if (!type1.IsInterface && !type1.IsDelegate) {
1163
for (int i = 0; i < targs_definition.Length; ++i) {
1164
if (TypeSpecComparer.IsEqual (t1_targs[i], t2_targs[i]))
1167
Variance v = targs_definition[i].Variance;
1168
if (v == Variance.None) {
1172
if (v == Variance.Covariant) {
1173
if (!Convert.ImplicitReferenceConversionExists (t1_targs[i], t2_targs[i]))
1175
} else if (!Convert.ImplicitReferenceConversionExists (t2_targs[i], t1_targs[i])) {
1185
// Checks whether two generic instances may become equal for some
1186
// particular instantiation (26.3.1).
1188
public static class Unify
1191
// Either @a or @b must be generic type
1193
public static bool IsEqual (TypeSpec a, TypeSpec b)
1195
if (a.MemberDefinition != b.MemberDefinition) {
1196
var base_ifaces = a.Interfaces;
1197
if (base_ifaces != null) {
1198
foreach (var base_iface in base_ifaces) {
1199
if (base_iface.Arity > 0 && IsEqual (base_iface, b))
1207
var ta = a.TypeArguments;
1208
var tb = b.TypeArguments;
1209
for (int i = 0; i < ta.Length; i++) {
1210
if (!MayBecomeEqualGenericTypes (ta[i], tb[i]))
1217
static bool ContainsTypeParameter (TypeSpec tparam, TypeSpec type)
1219
TypeSpec[] targs = type.TypeArguments;
1220
for (int i = 0; i < targs.Length; i++) {
1221
if (tparam == targs[i])
1224
if (ContainsTypeParameter (tparam, targs[i]))
1232
/// Check whether `a' and `b' may become equal generic types.
1233
/// The algorithm to do that is a little bit complicated.
1235
static bool MayBecomeEqualGenericTypes (TypeSpec a, TypeSpec b)
1237
if (a.IsGenericParameter) {
1239
// If a is an array of a's type, they may never
1246
// If b is a generic parameter or an actual type,
1247
// they may become equal:
1249
// class X<T,U> : I<T>, I<U>
1250
// class X<T> : I<T>, I<float>
1252
if (b.IsGenericParameter)
1253
return a != b && a.DeclaringType == b.DeclaringType;
1256
// We're now comparing a type parameter with a
1257
// generic instance. They may become equal unless
1258
// the type parameter appears anywhere in the
1259
// generic instance:
1261
// class X<T,U> : I<T>, I<X<U>>
1262
// -> error because you could instanciate it as
1265
// class X<T> : I<T>, I<X<T>> -> ok
1268
return !ContainsTypeParameter (a, b);
1271
if (b.IsGenericParameter)
1272
return MayBecomeEqualGenericTypes (b, a);
1275
// At this point, neither a nor b are a type parameter.
1277
// If one of them is a generic instance, compare them (if the
1278
// other one is not a generic instance, they can never
1281
if (TypeManager.IsGenericType (a) || TypeManager.IsGenericType (b))
1282
return IsEqual (a, b);
1285
// If both of them are arrays.
1287
var a_ac = a as ArrayContainer;
1289
var b_ac = b as ArrayContainer;
1290
if (b_ac == null || a_ac.Rank != b_ac.Rank)
1293
return MayBecomeEqualGenericTypes (a_ac.Element, b_ac.Element);
1297
// Ok, two ordinary types.
1303
public static bool Equals (TypeSpec[] x, TypeSpec[] y)
1308
if (x.Length != y.Length)
1311
for (int i = 0; i < x.Length; ++i)
1312
if (!IsEqual (x[i], y[i]))
1319
// Identity type conversion
1321
// Default reference comparison, it has to be used when comparing
1322
// two possible dynamic/internal types
1324
public static bool IsEqual (TypeSpec a, TypeSpec b)
1327
// This also rejects dynamic == dynamic
1328
return a.Kind != MemberKind.InternalCompilerType || a.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
1331
if (a == null || b == null)
1335
var a_a = (ArrayContainer) a;
1336
var b_a = b as ArrayContainer;
1340
return a_a.Rank == b_a.Rank && IsEqual (a_a.Element, b_a.Element);
1343
if (!a.IsGeneric || !b.IsGeneric) {
1345
// object and dynamic are considered equivalent there is an identity conversion
1346
// between object and dynamic, and between constructed types that are the same
1347
// when replacing all occurences of dynamic with object.
1349
if (a.BuiltinType == BuiltinTypeSpec.Type.Dynamic || b.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1350
return b.BuiltinType == BuiltinTypeSpec.Type.Object || a.BuiltinType == BuiltinTypeSpec.Type.Object;
1355
if (a.MemberDefinition != b.MemberDefinition)
1359
if (!Equals (a.TypeArguments, b.TypeArguments))
1362
a = a.DeclaringType;
1363
b = b.DeclaringType;
1364
} while (a != null);
1370
public interface ITypeDefinition : IMemberDefinition
1372
IAssemblyDefinition DeclaringAssembly { get; }
1373
string Namespace { get; }
1374
bool IsPartial { get; }
1375
bool IsComImport { get; }
1376
bool IsTypeForwarder { get; }
1377
int TypeParametersCount { get; }
1378
TypeParameterSpec[] TypeParameters { get; }
1380
TypeSpec GetAttributeCoClass ();
1381
string GetAttributeDefaultMember ();
1382
AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa);
1383
bool IsInternalAsPublic (IAssemblyDefinition assembly);
1384
void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache);
1387
class InternalType : TypeSpec, ITypeDefinition
1389
public static readonly InternalType AnonymousMethod = new InternalType ("anonymous method");
1390
public static readonly InternalType Arglist = new InternalType ("__arglist");
1391
public static readonly InternalType MethodGroup = new InternalType ("method group");
1392
public static readonly InternalType NullLiteral = new InternalType ("null");
1393
public static readonly InternalType FakeInternalType = new InternalType ("<fake$type>");
1394
public static readonly InternalType Namespace = new InternalType ("<namespace>");
1395
public static readonly InternalType ErrorType = new InternalType ("<error>");
1397
readonly string name;
1399
InternalType (string name)
1400
: base (MemberKind.InternalCompilerType, null, null, null, Modifiers.PUBLIC)
1403
this.definition = this;
1404
cache = MemberCache.Empty;
1406
// Make all internal types CLS-compliant, non-obsolete
1407
state = (state & ~(StateFlags.CLSCompliant_Undetected | StateFlags.Obsolete_Undetected | StateFlags.MissingDependency_Undetected)) | StateFlags.CLSCompliant;
1412
public override int Arity {
1418
IAssemblyDefinition ITypeDefinition.DeclaringAssembly {
1420
throw new NotImplementedException ();
1424
bool ITypeDefinition.IsComImport {
1430
bool IMemberDefinition.IsImported {
1436
bool ITypeDefinition.IsPartial {
1442
bool ITypeDefinition.IsTypeForwarder {
1448
public override string Name {
1454
string ITypeDefinition.Namespace {
1460
int ITypeDefinition.TypeParametersCount {
1466
TypeParameterSpec[] ITypeDefinition.TypeParameters {
1474
public override string GetSignatureForError ()
1479
#region ITypeDefinition Members
1481
TypeSpec ITypeDefinition.GetAttributeCoClass ()
1486
string ITypeDefinition.GetAttributeDefaultMember ()
1491
AttributeUsageAttribute ITypeDefinition.GetAttributeUsage (PredefinedAttribute pa)
1496
bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly)
1498
throw new NotImplementedException ();
1501
void ITypeDefinition.LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
1503
throw new NotImplementedException ();
1506
string[] IMemberDefinition.ConditionalConditions ()
1511
ObsoleteAttribute IMemberDefinition.GetAttributeObsolete ()
1516
bool? IMemberDefinition.CLSAttributeValue {
1522
void IMemberDefinition.SetIsAssigned ()
1526
void IMemberDefinition.SetIsUsed ()
1534
// Common base class for composite types
1536
public abstract class ElementTypeSpec : TypeSpec, ITypeDefinition
1538
protected ElementTypeSpec (MemberKind kind, TypeSpec element, MetaType info)
1539
: base (kind, element.DeclaringType, null, info, element.Modifiers)
1541
this.Element = element;
1543
state &= ~SharedStateFlags;
1544
state |= (element.state & SharedStateFlags);
1546
if (element.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1547
state |= StateFlags.HasDynamicElement;
1549
// Has to use its own type definition instead of just element definition to
1550
// correctly identify itself for cases like x.MemberDefininition == predefined.MemberDefinition
1551
this.definition = this;
1553
cache = MemberCache.Empty;
1558
public TypeSpec Element { get; private set; }
1560
bool ITypeDefinition.IsComImport {
1566
bool ITypeDefinition.IsPartial {
1572
bool ITypeDefinition.IsTypeForwarder {
1578
public override string Name {
1580
throw new NotSupportedException ();
1586
public override ObsoleteAttribute GetAttributeObsolete ()
1588
return Element.GetAttributeObsolete ();
1591
protected virtual string GetPostfixSignature ()
1596
public override string GetSignatureForDocumentation ()
1598
return Element.GetSignatureForDocumentation () + GetPostfixSignature ();
1601
public override string GetSignatureForError ()
1603
return Element.GetSignatureForError () + GetPostfixSignature ();
1606
public override TypeSpec Mutate (TypeParameterMutator mutator)
1608
var me = Element.Mutate (mutator);
1612
var mutated = (ElementTypeSpec) MemberwiseClone ();
1613
mutated.Element = me;
1614
mutated.info = null;
1618
#region ITypeDefinition Members
1620
IAssemblyDefinition ITypeDefinition.DeclaringAssembly {
1622
return Element.MemberDefinition.DeclaringAssembly;
1626
bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly)
1628
return Element.MemberDefinition.IsInternalAsPublic (assembly);
1631
public string Namespace {
1632
get { throw new NotImplementedException (); }
1635
public int TypeParametersCount {
1641
public TypeParameterSpec[] TypeParameters {
1643
throw new NotSupportedException ();
1647
public TypeSpec GetAttributeCoClass ()
1649
return Element.MemberDefinition.GetAttributeCoClass ();
1652
public string GetAttributeDefaultMember ()
1654
return Element.MemberDefinition.GetAttributeDefaultMember ();
1657
public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
1659
Element.MemberDefinition.LoadMembers (declaringType, onlyTypes, ref cache);
1662
public bool IsImported {
1664
return Element.MemberDefinition.IsImported;
1668
public string[] ConditionalConditions ()
1670
return Element.MemberDefinition.ConditionalConditions ();
1673
bool? IMemberDefinition.CLSAttributeValue {
1675
return Element.MemberDefinition.CLSAttributeValue;
1679
public void SetIsAssigned ()
1681
Element.MemberDefinition.SetIsAssigned ();
1684
public void SetIsUsed ()
1686
Element.MemberDefinition.SetIsUsed ();
1692
public class ArrayContainer : ElementTypeSpec
1694
public struct TypeRankPair : IEquatable<TypeRankPair>
1699
public TypeRankPair (TypeSpec ts, int rank)
1705
public override int GetHashCode ()
1707
return ts.GetHashCode () ^ rank.GetHashCode ();
1710
#region IEquatable<Tuple<T1,T2>> Members
1712
public bool Equals (TypeRankPair other)
1714
return other.ts == ts && other.rank == rank;
1721
readonly ModuleContainer module;
1723
private ArrayContainer (ModuleContainer module, TypeSpec element, int rank)
1724
: base (MemberKind.ArrayType, element, null)
1726
this.module = module;
1736
public MethodInfo GetConstructor ()
1738
var mb = module.Builder;
1740
var arg_types = new MetaType[rank];
1741
for (int i = 0; i < rank; i++)
1742
arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1744
var ctor = mb.GetArrayMethod (
1745
GetMetaInfo (), Constructor.ConstructorName,
1746
CallingConventions.HasThis,
1752
public MethodInfo GetAddressMethod ()
1754
var mb = module.Builder;
1756
var arg_types = new MetaType[rank];
1757
for (int i = 0; i < rank; i++)
1758
arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1760
var address = mb.GetArrayMethod (
1761
GetMetaInfo (), "Address",
1762
CallingConventions.HasThis | CallingConventions.Standard,
1763
ReferenceContainer.MakeType (module, Element).GetMetaInfo (), arg_types);
1768
public MethodInfo GetGetMethod ()
1770
var mb = module.Builder;
1772
var arg_types = new MetaType[rank];
1773
for (int i = 0; i < rank; i++)
1774
arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1776
var get = mb.GetArrayMethod (
1777
GetMetaInfo (), "Get",
1778
CallingConventions.HasThis | CallingConventions.Standard,
1779
Element.GetMetaInfo (), arg_types);
1784
public MethodInfo GetSetMethod ()
1786
var mb = module.Builder;
1788
var arg_types = new MetaType[rank + 1];
1789
for (int i = 0; i < rank; i++)
1790
arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1792
arg_types[rank] = Element.GetMetaInfo ();
1794
var set = mb.GetArrayMethod (
1795
GetMetaInfo (), "Set",
1796
CallingConventions.HasThis | CallingConventions.Standard,
1797
module.Compiler.BuiltinTypes.Void.GetMetaInfo (), arg_types);
1802
public override MetaType GetMetaInfo ()
1806
info = Element.GetMetaInfo ().MakeArrayType ();
1808
info = Element.GetMetaInfo ().MakeArrayType (rank);
1814
protected override string GetPostfixSignature()
1816
return GetPostfixSignature (rank);
1819
public static string GetPostfixSignature (int rank)
1821
StringBuilder sb = new StringBuilder ();
1823
for (int i = 1; i < rank; i++) {
1828
return sb.ToString ();
1831
public override string GetSignatureForDocumentation ()
1833
StringBuilder sb = new StringBuilder ();
1834
GetElementSignatureForDocumentation (sb);
1835
return sb.ToString ();
1838
void GetElementSignatureForDocumentation (StringBuilder sb)
1840
var ac = Element as ArrayContainer;
1842
sb.Append (Element.GetSignatureForDocumentation ());
1844
ac.GetElementSignatureForDocumentation (sb);
1847
for (int i = 1; i < rank; i++) {
1856
public static ArrayContainer MakeType (ModuleContainer module, TypeSpec element)
1858
return MakeType (module, element, 1);
1861
public static ArrayContainer MakeType (ModuleContainer module, TypeSpec element, int rank)
1864
var key = new TypeRankPair (element, rank);
1865
if (!module.ArrayTypesCache.TryGetValue (key, out ac)) {
1866
ac = new ArrayContainer (module, element, rank);
1867
ac.BaseType = module.Compiler.BuiltinTypes.Array;
1868
ac.Interfaces = ac.BaseType.Interfaces;
1870
module.ArrayTypesCache.Add (key, ac);
1877
class ReferenceContainer : ElementTypeSpec
1879
private ReferenceContainer (TypeSpec element)
1880
: base (MemberKind.Class, element, null) // TODO: Kind.Class is most likely wrong
1884
public override MetaType GetMetaInfo ()
1887
info = Element.GetMetaInfo ().MakeByRefType ();
1893
public static ReferenceContainer MakeType (ModuleContainer module, TypeSpec element)
1895
ReferenceContainer pc;
1896
if (!module.ReferenceTypesCache.TryGetValue (element, out pc)) {
1897
pc = new ReferenceContainer (element);
1898
module.ReferenceTypesCache.Add (element, pc);
1905
class PointerContainer : ElementTypeSpec
1907
private PointerContainer (TypeSpec element)
1908
: base (MemberKind.PointerType, element, null)
1910
// It's never CLS-Compliant
1911
state &= ~StateFlags.CLSCompliant_Undetected;
1914
public override MetaType GetMetaInfo ()
1917
info = Element.GetMetaInfo ().MakePointerType ();
1923
protected override string GetPostfixSignature()
1928
public static PointerContainer MakeType (ModuleContainer module, TypeSpec element)
1930
PointerContainer pc;
1931
if (!module.PointerTypesCache.TryGetValue (element, out pc)) {
1932
pc = new PointerContainer (element);
1933
module.PointerTypesCache.Add (element, pc);