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 (MemberDefinition.TypeParametersCount > 0) {
725
foreach (var tp in MemberDefinition.TypeParameters) {
726
var tp_missing = tp.GetMissingDependencies ();
727
if (tp_missing != null) {
729
missing = new List<TypeSpec> ();
731
missing.AddRange (tp_missing);
736
if (missing != null || BaseType == null)
739
return BaseType.ResolveMissingDependencies ();
742
public void SetMetaInfo (MetaType info)
744
if (this.info != null)
745
throw new InternalErrorException ("MetaInfo reset");
750
public void SetExtensionMethodContainer ()
752
modifiers |= Modifiers.METHOD_EXTENSION;
756
public sealed class BuiltinTypeSpec : TypeSpec
762
// Ordered carefully for fast compares
790
MulticastDelegate = 23,
803
readonly string name;
805
public BuiltinTypeSpec (MemberKind kind, string ns, string name, Type builtinKind)
806
: base (kind, null, null, null, Modifiers.PUBLIC)
808
this.type = builtinKind;
813
public BuiltinTypeSpec (string name, Type builtinKind)
814
: this (MemberKind.InternalCompilerType, "", name, builtinKind)
816
// Make all internal types CLS-compliant, non-obsolete, compact
817
state = (state & ~(StateFlags.CLSCompliant_Undetected | StateFlags.Obsolete_Undetected | StateFlags.MissingDependency_Undetected)) | StateFlags.CLSCompliant;
822
public override int Arity {
828
public override BuiltinTypeSpec.Type BuiltinType {
834
public string FullName {
836
return ns + '.' + name;
840
public override string Name {
846
public string Namespace {
854
public static bool IsPrimitiveType (TypeSpec type)
856
return type.BuiltinType >= Type.FirstPrimitive && type.BuiltinType <= Type.LastPrimitive;
859
public static bool IsPrimitiveTypeOrDecimal (TypeSpec type)
861
return type.BuiltinType >= Type.FirstPrimitive && type.BuiltinType <= Type.Decimal;
864
public override string GetSignatureForError ()
867
case "Int32": return "int";
868
case "Int64": return "long";
869
case "String": return "string";
870
case "Boolean": return "bool";
871
case "Void": return "void";
872
case "Object": return "object";
873
case "UInt32": return "uint";
874
case "Int16": return "short";
875
case "UInt16": return "ushort";
876
case "UInt64": return "ulong";
877
case "Single": return "float";
878
case "Double": return "double";
879
case "Decimal": return "decimal";
880
case "Char": return "char";
881
case "Byte": return "byte";
882
case "SByte": return "sbyte";
892
// Returns the size of type if known, otherwise, 0
894
public static int GetSize (TypeSpec type)
896
switch (type.BuiltinType) {
920
public void SetDefinition (ITypeDefinition td, MetaType type, Modifiers mod)
922
this.definition = td;
924
this.modifiers |= (mod & ~Modifiers.AccessibilityMask);
927
public void SetDefinition (TypeSpec ts)
929
this.definition = ts.MemberDefinition;
930
this.info = ts.GetMetaInfo ();
931
this.BaseType = ts.BaseType;
932
this.Interfaces = ts.Interfaces;
933
this.modifiers = ts.Modifiers;
937
static class TypeSpecComparer
940
// Does strict reference comparion only
942
public static readonly DefaultImpl Default = new DefaultImpl ();
944
public class DefaultImpl : IEqualityComparer<TypeSpec[]>
946
#region IEqualityComparer<TypeSpec[]> Members
948
bool IEqualityComparer<TypeSpec[]>.Equals (TypeSpec[] x, TypeSpec[] y)
953
if (x.Length != y.Length)
956
for (int i = 0; i < x.Length; ++i)
963
int IEqualityComparer<TypeSpec[]>.GetHashCode (TypeSpec[] obj)
966
for (int i = 0; i < obj.Length; ++i)
967
hash = (hash << 5) - hash + obj[i].GetHashCode ();
976
// When comparing type signature of overrides or overloads
977
// this version tolerates different MVARs at same position
979
public static class Override
981
public static bool IsEqual (TypeSpec a, TypeSpec b)
987
// Consider the following example:
989
// public abstract class A
991
// public abstract T Foo<T>();
994
// public class B : A
996
// public override U Foo<T>() { return default (U); }
999
// Here, `T' and `U' are method type parameters from different methods
1000
// (A.Foo and B.Foo), so both `==' and Equals() will fail.
1002
// However, since we're determining whether B.Foo() overrides A.Foo(),
1003
// we need to do a signature based comparision and consider them equal.
1006
var tp_a = a as TypeParameterSpec;
1008
var tp_b = b as TypeParameterSpec;
1009
return tp_b != null && tp_a.IsMethodOwned == tp_b.IsMethodOwned && tp_a.DeclaredPosition == tp_b.DeclaredPosition;
1012
var ac_a = a as ArrayContainer;
1014
var ac_b = b as ArrayContainer;
1015
return ac_b != null && ac_a.Rank == ac_b.Rank && IsEqual (ac_a.Element, ac_b.Element);
1018
if (a.BuiltinType == BuiltinTypeSpec.Type.Dynamic || b.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1019
return b.BuiltinType == BuiltinTypeSpec.Type.Object || a.BuiltinType == BuiltinTypeSpec.Type.Object;
1021
if (a.MemberDefinition != b.MemberDefinition)
1025
for (int i = 0; i < a.TypeArguments.Length; ++i) {
1026
if (!IsEqual (a.TypeArguments[i], b.TypeArguments[i]))
1030
a = a.DeclaringType;
1031
b = b.DeclaringType;
1032
} while (a != null);
1038
// Compares unordered arrays
1040
public static bool IsSame (TypeSpec[] a, TypeSpec[] b)
1045
if (a == null || b == null || a.Length != b.Length)
1048
for (int ai = 0; ai < a.Length; ++ai) {
1050
for (int bi = 0; bi < b.Length; ++bi) {
1051
if (IsEqual (a[ai], b[bi])) {
1064
public static bool IsEqual (AParametersCollection a, AParametersCollection b)
1069
if (a.Count != b.Count)
1072
for (int i = 0; i < a.Count; ++i) {
1073
if (!IsEqual (a.Types[i], b.Types[i]))
1076
if ((a.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (b.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
1085
// Type variance equality comparison
1087
public static class Variant
1089
public static bool IsEqual (TypeSpec type1, TypeSpec type2)
1091
if (!type1.IsGeneric || !type2.IsGeneric)
1094
var target_type_def = type2.MemberDefinition;
1095
if (type1.MemberDefinition != target_type_def)
1098
var t1_targs = type1.TypeArguments;
1099
var t2_targs = type2.TypeArguments;
1100
var targs_definition = target_type_def.TypeParameters;
1102
if (!type1.IsInterface && !type1.IsDelegate) {
1106
for (int i = 0; i < targs_definition.Length; ++i) {
1107
if (TypeSpecComparer.IsEqual (t1_targs[i], t2_targs[i]))
1110
Variance v = targs_definition[i].Variance;
1111
if (v == Variance.None) {
1115
if (v == Variance.Covariant) {
1116
if (!Convert.ImplicitReferenceConversionExists (t1_targs[i], t2_targs[i]))
1118
} else if (!Convert.ImplicitReferenceConversionExists (t2_targs[i], t1_targs[i])) {
1128
// Checks whether two generic instances may become equal for some
1129
// particular instantiation (26.3.1).
1131
public static class Unify
1134
// Either @a or @b must be generic type
1136
public static bool IsEqual (TypeSpec a, TypeSpec b)
1138
if (a.MemberDefinition != b.MemberDefinition) {
1139
var base_ifaces = a.Interfaces;
1140
if (base_ifaces != null) {
1141
foreach (var base_iface in base_ifaces) {
1142
if (base_iface.Arity > 0 && IsEqual (base_iface, b))
1150
var ta = a.TypeArguments;
1151
var tb = b.TypeArguments;
1152
for (int i = 0; i < ta.Length; i++) {
1153
if (!MayBecomeEqualGenericTypes (ta[i], tb[i]))
1160
static bool ContainsTypeParameter (TypeSpec tparam, TypeSpec type)
1162
TypeSpec[] targs = type.TypeArguments;
1163
for (int i = 0; i < targs.Length; i++) {
1164
if (tparam == targs[i])
1167
if (ContainsTypeParameter (tparam, targs[i]))
1175
/// Check whether `a' and `b' may become equal generic types.
1176
/// The algorithm to do that is a little bit complicated.
1178
static bool MayBecomeEqualGenericTypes (TypeSpec a, TypeSpec b)
1180
if (a.IsGenericParameter) {
1182
// If a is an array of a's type, they may never
1189
// If b is a generic parameter or an actual type,
1190
// they may become equal:
1192
// class X<T,U> : I<T>, I<U>
1193
// class X<T> : I<T>, I<float>
1195
if (b.IsGenericParameter)
1196
return a != b && a.DeclaringType == b.DeclaringType;
1199
// We're now comparing a type parameter with a
1200
// generic instance. They may become equal unless
1201
// the type parameter appears anywhere in the
1202
// generic instance:
1204
// class X<T,U> : I<T>, I<X<U>>
1205
// -> error because you could instanciate it as
1208
// class X<T> : I<T>, I<X<T>> -> ok
1211
return !ContainsTypeParameter (a, b);
1214
if (b.IsGenericParameter)
1215
return MayBecomeEqualGenericTypes (b, a);
1218
// At this point, neither a nor b are a type parameter.
1220
// If one of them is a generic instance, compare them (if the
1221
// other one is not a generic instance, they can never
1224
if (TypeManager.IsGenericType (a) || TypeManager.IsGenericType (b))
1225
return IsEqual (a, b);
1228
// If both of them are arrays.
1230
var a_ac = a as ArrayContainer;
1232
var b_ac = b as ArrayContainer;
1233
if (b_ac == null || a_ac.Rank != b_ac.Rank)
1236
return MayBecomeEqualGenericTypes (a_ac.Element, b_ac.Element);
1240
// Ok, two ordinary types.
1246
public static bool Equals (TypeSpec[] x, TypeSpec[] y)
1251
if (x.Length != y.Length)
1254
for (int i = 0; i < x.Length; ++i)
1255
if (!IsEqual (x[i], y[i]))
1262
// Identity type conversion
1264
// Default reference comparison, it has to be used when comparing
1265
// two possible dynamic/internal types
1267
public static bool IsEqual (TypeSpec a, TypeSpec b)
1270
// This also rejects dynamic == dynamic
1271
return a.Kind != MemberKind.InternalCompilerType || a.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
1274
if (a == null || b == null)
1278
var a_a = (ArrayContainer) a;
1279
var b_a = b as ArrayContainer;
1283
return a_a.Rank == b_a.Rank && IsEqual (a_a.Element, b_a.Element);
1286
if (!a.IsGeneric || !b.IsGeneric) {
1288
// object and dynamic are considered equivalent there is an identity conversion
1289
// between object and dynamic, and between constructed types that are the same
1290
// when replacing all occurences of dynamic with object.
1292
if (a.BuiltinType == BuiltinTypeSpec.Type.Dynamic || b.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1293
return b.BuiltinType == BuiltinTypeSpec.Type.Object || a.BuiltinType == BuiltinTypeSpec.Type.Object;
1298
if (a.MemberDefinition != b.MemberDefinition)
1302
if (!Equals (a.TypeArguments, b.TypeArguments))
1305
a = a.DeclaringType;
1306
b = b.DeclaringType;
1307
} while (a != null);
1313
public interface ITypeDefinition : IMemberDefinition
1315
IAssemblyDefinition DeclaringAssembly { get; }
1316
string Namespace { get; }
1317
bool IsPartial { get; }
1318
int TypeParametersCount { get; }
1319
TypeParameterSpec[] TypeParameters { get; }
1321
TypeSpec GetAttributeCoClass ();
1322
string GetAttributeDefaultMember ();
1323
AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa);
1324
bool IsInternalAsPublic (IAssemblyDefinition assembly);
1325
void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache);
1328
class InternalType : TypeSpec, ITypeDefinition
1330
public static readonly InternalType AnonymousMethod = new InternalType ("anonymous method");
1331
public static readonly InternalType Arglist = new InternalType ("__arglist");
1332
public static readonly InternalType MethodGroup = new InternalType ("method group");
1333
public static readonly InternalType NullLiteral = new InternalType ("null");
1334
public static readonly InternalType FakeInternalType = new InternalType ("<fake$type>");
1335
public static readonly InternalType Namespace = new InternalType ("<namespace>");
1336
public static readonly InternalType ErrorType = new InternalType ("<error>");
1338
readonly string name;
1340
InternalType (string name)
1341
: base (MemberKind.InternalCompilerType, null, null, null, Modifiers.PUBLIC)
1344
this.definition = this;
1345
cache = MemberCache.Empty;
1347
// Make all internal types CLS-compliant, non-obsolete
1348
state = (state & ~(StateFlags.CLSCompliant_Undetected | StateFlags.Obsolete_Undetected | StateFlags.MissingDependency_Undetected)) | StateFlags.CLSCompliant;
1353
public override int Arity {
1359
IAssemblyDefinition ITypeDefinition.DeclaringAssembly {
1361
throw new NotImplementedException ();
1365
bool IMemberDefinition.IsImported {
1371
bool ITypeDefinition.IsPartial {
1377
public override string Name {
1383
string ITypeDefinition.Namespace {
1389
int ITypeDefinition.TypeParametersCount {
1395
TypeParameterSpec[] ITypeDefinition.TypeParameters {
1403
public override string GetSignatureForError ()
1408
#region ITypeDefinition Members
1410
TypeSpec ITypeDefinition.GetAttributeCoClass ()
1415
string ITypeDefinition.GetAttributeDefaultMember ()
1420
AttributeUsageAttribute ITypeDefinition.GetAttributeUsage (PredefinedAttribute pa)
1425
bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly)
1427
throw new NotImplementedException ();
1430
void ITypeDefinition.LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
1432
throw new NotImplementedException ();
1435
string[] IMemberDefinition.ConditionalConditions ()
1440
ObsoleteAttribute IMemberDefinition.GetAttributeObsolete ()
1445
bool? IMemberDefinition.CLSAttributeValue {
1451
void IMemberDefinition.SetIsAssigned ()
1455
void IMemberDefinition.SetIsUsed ()
1462
public abstract class ElementTypeSpec : TypeSpec, ITypeDefinition
1464
protected ElementTypeSpec (MemberKind kind, TypeSpec element, MetaType info)
1465
: base (kind, element.DeclaringType, null, info, element.Modifiers)
1467
this.Element = element;
1469
state &= ~SharedStateFlags;
1470
state |= (element.state & SharedStateFlags);
1472
if (element.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1473
state |= StateFlags.HasDynamicElement;
1475
// Has to use its own type definition instead of just element definition to
1476
// correctly identify itself for cases like x.MemberDefininition == predefined.MemberDefinition
1477
this.definition = this;
1479
cache = MemberCache.Empty;
1484
public TypeSpec Element { get; private set; }
1486
bool ITypeDefinition.IsPartial {
1492
public override string Name {
1494
throw new NotSupportedException ();
1500
public override ObsoleteAttribute GetAttributeObsolete ()
1502
return Element.GetAttributeObsolete ();
1505
protected virtual string GetPostfixSignature ()
1510
public override string GetSignatureForDocumentation ()
1512
return Element.GetSignatureForDocumentation () + GetPostfixSignature ();
1515
public override string GetSignatureForError ()
1517
return Element.GetSignatureForError () + GetPostfixSignature ();
1520
public override TypeSpec Mutate (TypeParameterMutator mutator)
1522
var me = Element.Mutate (mutator);
1526
var mutated = (ElementTypeSpec) MemberwiseClone ();
1527
mutated.Element = me;
1528
mutated.info = null;
1532
#region ITypeDefinition Members
1534
IAssemblyDefinition ITypeDefinition.DeclaringAssembly {
1536
return Element.MemberDefinition.DeclaringAssembly;
1540
bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly)
1542
return Element.MemberDefinition.IsInternalAsPublic (assembly);
1545
public string Namespace {
1546
get { throw new NotImplementedException (); }
1549
public int TypeParametersCount {
1555
public TypeParameterSpec[] TypeParameters {
1557
throw new NotSupportedException ();
1561
public TypeSpec GetAttributeCoClass ()
1563
return Element.MemberDefinition.GetAttributeCoClass ();
1566
public string GetAttributeDefaultMember ()
1568
return Element.MemberDefinition.GetAttributeDefaultMember ();
1571
public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
1573
Element.MemberDefinition.LoadMembers (declaringType, onlyTypes, ref cache);
1576
public bool IsImported {
1578
return Element.MemberDefinition.IsImported;
1582
public string[] ConditionalConditions ()
1584
return Element.MemberDefinition.ConditionalConditions ();
1587
bool? IMemberDefinition.CLSAttributeValue {
1589
return Element.MemberDefinition.CLSAttributeValue;
1593
public void SetIsAssigned ()
1595
Element.MemberDefinition.SetIsAssigned ();
1598
public void SetIsUsed ()
1600
Element.MemberDefinition.SetIsUsed ();
1606
public class ArrayContainer : ElementTypeSpec
1608
public struct TypeRankPair : IEquatable<TypeRankPair>
1613
public TypeRankPair (TypeSpec ts, int rank)
1619
public override int GetHashCode ()
1621
return ts.GetHashCode () ^ rank.GetHashCode ();
1624
#region IEquatable<Tuple<T1,T2>> Members
1626
public bool Equals (TypeRankPair other)
1628
return other.ts == ts && other.rank == rank;
1635
readonly ModuleContainer module;
1637
private ArrayContainer (ModuleContainer module, TypeSpec element, int rank)
1638
: base (MemberKind.ArrayType, element, null)
1640
this.module = module;
1650
public MethodInfo GetConstructor ()
1652
var mb = module.Builder;
1654
var arg_types = new MetaType[rank];
1655
for (int i = 0; i < rank; i++)
1656
arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1658
var ctor = mb.GetArrayMethod (
1659
GetMetaInfo (), Constructor.ConstructorName,
1660
CallingConventions.HasThis,
1666
public MethodInfo GetAddressMethod ()
1668
var mb = module.Builder;
1670
var arg_types = new MetaType[rank];
1671
for (int i = 0; i < rank; i++)
1672
arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1674
var address = mb.GetArrayMethod (
1675
GetMetaInfo (), "Address",
1676
CallingConventions.HasThis | CallingConventions.Standard,
1677
ReferenceContainer.MakeType (module, Element).GetMetaInfo (), arg_types);
1682
public MethodInfo GetGetMethod ()
1684
var mb = module.Builder;
1686
var arg_types = new MetaType[rank];
1687
for (int i = 0; i < rank; i++)
1688
arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1690
var get = mb.GetArrayMethod (
1691
GetMetaInfo (), "Get",
1692
CallingConventions.HasThis | CallingConventions.Standard,
1693
Element.GetMetaInfo (), arg_types);
1698
public MethodInfo GetSetMethod ()
1700
var mb = module.Builder;
1702
var arg_types = new MetaType[rank + 1];
1703
for (int i = 0; i < rank; i++)
1704
arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1706
arg_types[rank] = Element.GetMetaInfo ();
1708
var set = mb.GetArrayMethod (
1709
GetMetaInfo (), "Set",
1710
CallingConventions.HasThis | CallingConventions.Standard,
1711
module.Compiler.BuiltinTypes.Void.GetMetaInfo (), arg_types);
1716
public override MetaType GetMetaInfo ()
1720
info = Element.GetMetaInfo ().MakeArrayType ();
1722
info = Element.GetMetaInfo ().MakeArrayType (rank);
1728
protected override string GetPostfixSignature()
1730
return GetPostfixSignature (rank);
1733
public static string GetPostfixSignature (int rank)
1735
StringBuilder sb = new StringBuilder ();
1737
for (int i = 1; i < rank; i++) {
1742
return sb.ToString ();
1745
public override string GetSignatureForDocumentation ()
1747
StringBuilder sb = new StringBuilder ();
1748
GetElementSignatureForDocumentation (sb);
1749
return sb.ToString ();
1752
void GetElementSignatureForDocumentation (StringBuilder sb)
1754
var ac = Element as ArrayContainer;
1756
sb.Append (Element.GetSignatureForDocumentation ());
1758
ac.GetElementSignatureForDocumentation (sb);
1761
for (int i = 1; i < rank; i++) {
1770
public static ArrayContainer MakeType (ModuleContainer module, TypeSpec element)
1772
return MakeType (module, element, 1);
1775
public static ArrayContainer MakeType (ModuleContainer module, TypeSpec element, int rank)
1778
var key = new TypeRankPair (element, rank);
1779
if (!module.ArrayTypesCache.TryGetValue (key, out ac)) {
1780
ac = new ArrayContainer (module, element, rank) {
1781
BaseType = module.Compiler.BuiltinTypes.Array
1784
module.ArrayTypesCache.Add (key, ac);
1791
class ReferenceContainer : ElementTypeSpec
1793
private ReferenceContainer (TypeSpec element)
1794
: base (MemberKind.Class, element, null) // TODO: Kind.Class is most likely wrong
1798
public override MetaType GetMetaInfo ()
1801
info = Element.GetMetaInfo ().MakeByRefType ();
1807
public static ReferenceContainer MakeType (ModuleContainer module, TypeSpec element)
1809
ReferenceContainer pc;
1810
if (!module.ReferenceTypesCache.TryGetValue (element, out pc)) {
1811
pc = new ReferenceContainer (element);
1812
module.ReferenceTypesCache.Add (element, pc);
1819
class PointerContainer : ElementTypeSpec
1821
private PointerContainer (TypeSpec element)
1822
: base (MemberKind.PointerType, element, null)
1824
// It's never CLS-Compliant
1825
state &= ~StateFlags.CLSCompliant_Undetected;
1828
public override MetaType GetMetaInfo ()
1831
info = Element.GetMetaInfo ().MakePointerType ();
1837
protected override string GetPostfixSignature()
1842
public static PointerContainer MakeType (ModuleContainer module, TypeSpec element)
1844
PointerContainer pc;
1845
if (!module.PointerTypesCache.TryGetValue (element, out pc)) {
1846
pc = new PointerContainer (element);
1847
module.PointerTypesCache.Add (element, pc);