Allow imported members cache to be setup in 2 phases as compiled one is to deal with...
[mono.git] / mcs / mcs / typespec.cs
1 //
2 // typespec.cs: Type specification
3 //
4 // Authors: Marek Safar (marek.safar@gmail.com)
5 //
6 // Dual licensed under the terms of the MIT X11 or GNU GPL
7 //
8 // Copyright 2010 Novell, Inc
9 //
10
11 using System;
12 using System.Collections.Generic;
13 using System.Text;
14 using System.Linq;
15
16 namespace Mono.CSharp
17 {
18         public class TypeSpec : MemberSpec
19         {
20                 protected Type info;
21                 protected MemberCache cache;
22                 protected IList<TypeSpec> ifaces;
23                 TypeSpec base_type;
24
25                 Dictionary<TypeSpec[], InflatedTypeSpec> inflated_instances;
26
27                 public static readonly TypeSpec[] EmptyTypes = new TypeSpec[0];
28
29                 // Reflection Emit hacking
30                 static Type TypeBuilder;
31                 static Type GenericTypeBuilder;
32
33                 static TypeSpec ()
34                 {
35                         var assembly = typeof (object).Assembly;
36                         TypeBuilder = assembly.GetType ("System.Reflection.Emit.TypeBuilder");
37                         GenericTypeBuilder = assembly.GetType ("System.Reflection.MonoGenericClass");
38                         if (GenericTypeBuilder == null)
39                                 GenericTypeBuilder = assembly.GetType ("System.Reflection.Emit.TypeBuilderInstantiation");
40                 }
41
42                 public TypeSpec (MemberKind kind, TypeSpec declaringType, ITypeDefinition definition, Type info, Modifiers modifiers)
43                         : base (kind, declaringType, definition, modifiers)
44                 {
45                         this.declaringType = declaringType;
46                         this.info = info;
47
48                         if (definition != null && definition.TypeParametersCount > 0)
49                                 state |= StateFlags.IsGeneric;
50                 }
51
52                 #region Properties
53
54                 public override int Arity {
55                         get {
56                                 return MemberDefinition.TypeParametersCount;
57                         }
58                 }
59
60                 public virtual TypeSpec BaseType {
61                         get {
62                                 return base_type;
63                         }
64                         set {
65                                 base_type = value;
66                         }
67                 }
68
69                 public virtual IList<TypeSpec> Interfaces {
70                         get {
71                                 return ifaces;
72                         }
73                         set {
74                                 ifaces = value;
75                         }
76                 }
77
78                 public bool IsArray {
79                         get {
80                                 return Kind == MemberKind.ArrayType;
81                         }
82                 }
83
84                 public bool IsAttribute {
85                         get {
86                                 if (!IsClass)
87                                         return false;
88
89                                 var type = this;
90                                 do {
91                                         if (type.IsGeneric)
92                                                 return false;
93
94                                         if (type == TypeManager.attribute_type)
95                                                 return true;
96                                         
97                                         type = type.base_type;
98                                 } while (type != null);
99
100                                 return false;
101                         }
102                 }
103
104                 public bool IsInterface {
105                         get {
106                                 return Kind == MemberKind.Interface;
107                         }
108                 }
109
110                 public bool IsClass {
111                         get {
112                                 return Kind == MemberKind.Class;
113                         }
114                 }
115
116                 public bool IsConstantCompatible {
117                         get {
118                                 if ((Kind & (MemberKind.Enum | MemberKind.Class | MemberKind.Interface | MemberKind.Delegate | MemberKind.ArrayType)) != 0)
119                                         return true;
120
121                                 return TypeManager.IsPrimitiveType (this) || this == TypeManager.decimal_type || this == InternalType.Dynamic;
122                         }
123                 }
124
125                 public bool IsDelegate {
126                         get {
127                                 return Kind == MemberKind.Delegate;
128                         }
129                 }
130
131                 public bool IsEnum {
132                         get { return Kind == MemberKind.Enum; }
133                 }
134
135                 // TODO: Should probably do
136                 // IsGenericType -- recursive
137                 // HasTypeParameter -- non-recursive
138                 public bool IsGenericOrParentIsGeneric {
139                         get {
140                                 var ts = this;
141                                 do {
142                                         if (ts.IsGeneric)
143                                                 return true;
144                                         ts = ts.declaringType;
145                                 } while (ts != null);
146
147                                 return false;
148                         }
149                 }
150
151                 public bool IsGenericParameter {
152                         get { return Kind == MemberKind.TypeParameter; }
153                 }
154
155                 public bool IsNested {
156                         get { return declaringType != null && Kind != MemberKind.TypeParameter; }
157                 }
158
159                 public bool IsPointer {
160                         get {
161                                 return Kind == MemberKind.PointerType;
162                         }
163                 }
164
165                 public bool IsSealed {
166                         get { return (Modifiers & Modifiers.SEALED) != 0; }
167                 }
168
169                 public bool IsStruct {
170                         get { 
171                                 return Kind == MemberKind.Struct;
172                         }
173                 }
174
175                 public bool IsTypeBuilder {
176                         get {
177                                 var meta = GetMetaInfo().GetType ();
178                                 return meta == TypeBuilder || meta == GenericTypeBuilder;
179                         }
180                 }
181
182                 public MemberCache MemberCache {
183                         get {
184                                 if (cache == null || (state & StateFlags.PendingMemberCacheMembers) != 0)
185                                         InitializeMemberCache (false);
186
187                                 return cache;
188                         }
189                         set {
190                                 if (cache != null)
191                                         throw new InternalErrorException ("Membercache reset");
192
193                                 cache = value;
194                         }
195                 }
196
197                 public MemberCache MemberCacheTypes {
198                         get {
199                                 if (cache == null)
200                                         InitializeMemberCache (true);
201
202                                 return cache;
203                         }
204                 }       
205
206                 public new ITypeDefinition MemberDefinition {
207                         get {
208                                 return (ITypeDefinition) definition;
209                         }
210                 }
211
212                 // TODO: Wouldn't be better to rely on cast to InflatedTypeSpec and
213                 // remove the property, YES IT WOULD !!!
214                 public virtual TypeSpec[] TypeArguments {
215                         get { return TypeSpec.EmptyTypes; }
216                 }
217
218                 #endregion
219
220                 public bool AddInterface (TypeSpec iface)
221                 {
222                         if ((state & StateFlags.InterfacesExpanded) != 0)
223                                 throw new InternalErrorException ("Modifying expanded interface list");
224
225                         if (ifaces == null) {
226                                 ifaces = new List<TypeSpec> () { iface };
227                                 return true;
228                         }
229
230                         if (!ifaces.Contains (iface)) {
231                                 ifaces.Add (iface);
232                                 return true;
233                         }
234
235                         return false;
236                 }
237
238                 public AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa)
239                 {
240                         if (Kind != MemberKind.Class)
241                                 throw new InternalErrorException ();
242
243                         if (!pa.IsDefined)
244                                 return Attribute.DefaultUsageAttribute;
245
246                         AttributeUsageAttribute aua = null;
247                         var type = this;
248                         while (type != null) {
249                                 aua = type.MemberDefinition.GetAttributeUsage (pa);
250                                 if (aua != null)
251                                         break;
252
253                                 type = type.BaseType;
254                         }
255
256                         return aua;
257                 }
258
259                 public virtual Type GetMetaInfo ()
260                 {
261                         return info;
262                 }
263
264                 public virtual TypeSpec GetDefinition ()
265                 {
266                         return this;
267                 }
268
269                 public override string GetSignatureForError ()
270                 {
271                         string s;
272
273                         if (IsNested) {
274                                 s = DeclaringType.GetSignatureForError ();
275                         } else if (MemberDefinition is AnonymousTypeClass) {
276                                 return ((AnonymousTypeClass) MemberDefinition).GetSignatureForError ();
277                         } else {
278                                 s = MemberDefinition.Namespace;
279                         }
280
281                         if (!string.IsNullOrEmpty (s))
282                                 s += ".";
283
284                         return s + Name + GetTypeNameSignature ();
285                 }
286
287                 protected virtual string GetTypeNameSignature ()
288                 {
289                         if (!IsGeneric)
290                                 return null;
291
292                         return "<" + TypeManager.CSharpName (MemberDefinition.TypeParameters) + ">";
293                 }
294
295                 public bool ImplementsInterface (TypeSpec iface, bool variantly)
296                 {
297                         var t = this;
298                         do {
299                                 if (t.Interfaces != null) {     // TODO: Try t.iface
300                                         foreach (TypeSpec i in t.Interfaces) {
301                                                 if (i == iface || TypeSpecComparer.IsEqual (i, iface))
302                                                         return true;
303
304                                                 if (variantly && TypeSpecComparer.Variant.IsEqual (i, iface))
305                                                         return true;
306                                         }
307                                 }
308
309                                 t = t.BaseType;
310                         } while (t != null);
311
312                         return false;
313                 }
314
315                 protected virtual void InitializeMemberCache (bool onlyTypes)
316                 {
317                         MemberDefinition.LoadMembers (this, onlyTypes, ref cache);
318
319                         if (onlyTypes)
320                                 state |= StateFlags.PendingMemberCacheMembers;
321                         else
322                                 state &= ~StateFlags.PendingMemberCacheMembers;
323                 }
324
325                 //
326                 // Is @baseClass base implementation of @type. With enabled @dynamicIsEqual the slower
327                 // comparison is used to hide differences between `object' and `dynamic' for generic
328                 // types. Should not be used for comparisons where G<object> != G<dynamic>
329                 //
330                 public static bool IsBaseClass (TypeSpec type, TypeSpec baseClass, bool dynamicIsObject)
331                 {
332                         if (dynamicIsObject && baseClass.IsGeneric) {
333                                 //
334                                 // Returns true for a hierarchies like this when passing baseClass of A<dynamic>
335                                 //
336                                 // class B : A<object> {}
337                                 //
338                                 while (type != null) {
339                                         type = type.BaseType;
340                                         if (TypeSpecComparer.IsEqual (type, baseClass))
341                                                 return true;
342                                 }
343
344                                 return false;
345                         }
346
347                         while (type != null) {
348                                 type = type.BaseType;
349                                 if (type == baseClass)
350                                         return true;
351                         }
352
353                         return false;
354                 }
355
356                 public override MemberSpec InflateMember (TypeParameterInflator inflator)
357                 {
358                         var targs = IsGeneric ? MemberDefinition.TypeParameters : TypeSpec.EmptyTypes;
359
360                         //
361                         // When inflating nested type from inside the type instance will be same
362                         // because type parameters are same for all nested types
363                         //
364                         if (DeclaringType == inflator.TypeInstance)
365                                 return MakeGenericType (targs);
366
367                         return new InflatedTypeSpec (this, inflator.TypeInstance, targs);
368                 }
369
370                 public InflatedTypeSpec MakeGenericType (TypeSpec[] targs)
371                 {
372                         if (targs.Length == 0 && !IsNested)
373                                 throw new ArgumentException ("Empty type arguments for type " + GetSignatureForError ());
374
375                         InflatedTypeSpec instance;
376
377                         if (inflated_instances == null)
378                                 inflated_instances = new Dictionary<TypeSpec[], InflatedTypeSpec> (TypeSpecComparer.Default);
379
380                         if (!inflated_instances.TryGetValue (targs, out instance)) {
381                                 if (GetDefinition () != this && !IsNested)
382                                         throw new InternalErrorException ("`{0}' must be type definition or nested non-inflated type to MakeGenericType",
383                                                 GetSignatureForError ());
384
385                                 instance = new InflatedTypeSpec (this, declaringType, targs);
386                                 inflated_instances.Add (targs, instance);
387                         }
388
389                         return instance;
390                 }
391
392                 public virtual TypeSpec Mutate (TypeParameterMutator mutator)
393                 {
394                         return this;
395                 }
396
397                 public void SetMetaInfo (Type info)
398                 {
399                         if (this.info != null)
400                                 throw new InternalErrorException ("MetaInfo reset");
401
402                         this.info = info;
403                 }
404
405                 public void SetExtensionMethodContainer ()
406                 {
407                         modifiers |= Modifiers.METHOD_EXTENSION;
408                 }
409         }
410
411         public class PredefinedTypeSpec : TypeSpec
412         {
413                 string name;
414                 string ns;
415
416                 public PredefinedTypeSpec (MemberKind kind, string ns, string name)
417                         : base (kind, null, null, null, Modifiers.PUBLIC)
418                 {
419                         this.name = name;
420                         this.ns = ns;
421                 }
422
423                 #region Properties
424
425                 public override int Arity {
426                         get {
427                                 return 0;
428                         }
429                 }
430
431                 public override string Name {
432                         get {
433                                 return name;
434                         }
435                 }
436
437                 public string Namespace {
438                         get {
439                                 return ns;
440                         }
441                 }
442
443                 #endregion
444
445                 public override string GetSignatureForError ()
446                 {
447                         switch (name) {
448                         case "Int32": return "int";
449                         case "Int64": return "long";
450                         case "String": return "string";
451                         case "Boolean": return "bool";
452                         case "Void": return "void";
453                         case "Object": return "object";
454                         case "UInt32": return "uint";
455                         case "Int16": return "short";
456                         case "UInt16": return "ushort";
457                         case "UInt64": return "ulong";
458                         case "Single": return "float";
459                         case "Double": return "double";
460                         case "Decimal": return "decimal";
461                         case "Char": return "char";
462                         case "Byte": return "byte";
463                         case "SByte": return "sbyte";
464                         }
465
466                         return ns + "." + name;
467                 }
468
469                 public void SetDefinition (ITypeDefinition td, Type type)
470                 {
471                         this.definition = td;
472                         this.info = type;
473                 }
474
475                 public void SetDefinition (TypeSpec ts)
476                 {
477                         this.definition = ts.MemberDefinition;
478                         this.info = ts.GetMetaInfo ();
479                         this.BaseType = ts.BaseType;
480                         this.Interfaces = ts.Interfaces;
481                 }
482         }
483
484         static class TypeSpecComparer
485         {
486                 //
487                 // Does strict reference comparion only
488                 //
489                 public static readonly DefaultImpl Default = new DefaultImpl ();
490
491                 public class DefaultImpl : IEqualityComparer<TypeSpec[]>
492                 {
493                         #region IEqualityComparer<TypeSpec[]> Members
494
495                         bool IEqualityComparer<TypeSpec[]>.Equals (TypeSpec[] x, TypeSpec[] y)
496                         {
497                                 if (x == y)
498                                         return true;
499
500                                 if (x.Length != y.Length)
501                                         return false;
502
503                                 for (int i = 0; i < x.Length; ++i)
504                                         if (x[i] != y[i])
505                                                 return false;
506
507                                 return true;
508                         }
509
510                         int IEqualityComparer<TypeSpec[]>.GetHashCode (TypeSpec[] obj)
511                         {
512                                 int hash = 0;
513                                 for (int i = 0; i < obj.Length; ++i)
514                                         hash = (hash << 5) - hash + obj[i].GetHashCode ();
515
516                                 return hash;
517                         }
518
519                         #endregion
520                 }
521
522                 //
523                 // When comparing type signature of overrides or overloads
524                 // this version tolerates different MVARs at same position
525                 //
526                 public static class Override
527                 {
528                         public static bool IsEqual (TypeSpec a, TypeSpec b)
529                         {
530                                 if (a == b)
531                                         return true;
532
533                                 //
534                                 // Consider the following example:
535                                 //
536                                 //     public abstract class A
537                                 //     {
538                                 //        public abstract T Foo<T>();
539                                 //     }
540                                 //
541                                 //     public class B : A
542                                 //     {
543                                 //        public override U Foo<T>() { return default (U); }
544                                 //     }
545                                 //
546                                 // Here, `T' and `U' are method type parameters from different methods
547                                 // (A.Foo and B.Foo), so both `==' and Equals() will fail.
548                                 //
549                                 // However, since we're determining whether B.Foo() overrides A.Foo(),
550                                 // we need to do a signature based comparision and consider them equal.
551                                 //
552
553                                 var tp_a = a as TypeParameterSpec;
554                                 if (tp_a != null) {
555                                         var tp_b = b as TypeParameterSpec;
556                                         return tp_b != null && tp_a.IsMethodOwned == tp_b.IsMethodOwned && tp_a.DeclaredPosition == tp_b.DeclaredPosition;
557                                 }
558
559                                 if (a.TypeArguments.Length != b.TypeArguments.Length)
560                                         return false;
561
562                                 if (a.TypeArguments.Length != 0) {
563                                         if (a.MemberDefinition != b.MemberDefinition)
564                                                 return false;
565
566                                         for (int i = 0; i < a.TypeArguments.Length; ++i) {
567                                                 if (!IsEqual (a.TypeArguments[i], b.TypeArguments[i]))
568                                                         return false;
569                                         }
570
571                                         return true;
572                                 }
573
574                                 var ac_a = a as ArrayContainer;
575                                 if (ac_a != null) {
576                                         var ac_b = b as ArrayContainer;
577                                         return ac_b != null && ac_a.Rank == ac_b.Rank && IsEqual (ac_a.Element, ac_b.Element);
578                                 }
579
580                                 if (a == InternalType.Dynamic || b == InternalType.Dynamic)
581                                         return b == TypeManager.object_type || a == TypeManager.object_type;
582
583                                 return false;
584                         }
585
586                         //
587                         // Compares unordered arrays
588                         //
589                         public static bool IsSame (TypeSpec[] a, TypeSpec[] b)
590                         {
591                                 if (a == b)
592                                         return true;
593
594                                 if (a == null || b == null || a.Length != b.Length)
595                                         return false;
596
597                                 for (int ai = 0; ai < a.Length; ++ai) {
598                                         bool found = false;
599                                         for (int bi = 0; bi < b.Length; ++bi) {
600                                                 if (IsEqual (a[ai], b[bi])) {
601                                                         found = true;
602                                                         break;
603                                                 }
604                                         }
605
606                                         if (!found)
607                                                 return false;
608                                 }
609
610                                 return true;
611                         }
612
613                         public static bool IsEqual (AParametersCollection a, AParametersCollection b)
614                         {
615                                 if (a == b)
616                                         return true;
617
618                                 if (a.Count != b.Count)
619                                         return false;
620
621                                 for (int i = 0; i < a.Count; ++i) {
622                                         if (!IsEqual (a.Types[i], b.Types[i]))
623                                                 return false;
624
625                                         const Parameter.Modifier ref_out = Parameter.Modifier.REF | Parameter.Modifier.OUT;
626                                         if ((a.FixedParameters[i].ModFlags & ref_out) != (b.FixedParameters[i].ModFlags & ref_out))
627                                                 return false;
628                                 }
629
630                                 return true;
631                         }
632                 }
633
634                 //
635                 // Type variance equality comparison
636                 //
637                 public static class Variant
638                 {
639                         public static bool IsEqual (TypeSpec type1, TypeSpec type2)
640                         {
641                                 if (!type1.IsGeneric || !type2.IsGeneric)
642                                         return false;
643
644                                 var target_type_def = type2.MemberDefinition;
645                                 if (type1.MemberDefinition != target_type_def)
646                                         return false;
647
648                                 var t1_targs = type1.TypeArguments;
649                                 var t2_targs = type2.TypeArguments;
650                                 var targs_definition = target_type_def.TypeParameters;
651
652                                 if (!type1.IsInterface && !type1.IsDelegate) {
653                                         return false;
654                                 }
655
656                                 for (int i = 0; i < targs_definition.Length; ++i) {
657                                         Variance v = targs_definition[i].Variance;
658                                         if (v == Variance.None) {
659                                                 if (t1_targs[i] == t2_targs[i])
660                                                         continue;
661                                                 return false;
662                                         }
663
664                                         if (v == Variance.Covariant) {
665                                                 if (!Convert.ImplicitReferenceConversionExists (new EmptyExpression (t1_targs[i]), t2_targs[i]))
666                                                         return false;
667                                         } else if (!Convert.ImplicitReferenceConversionExists (new EmptyExpression (t2_targs[i]), t1_targs[i])) {
668                                                 return false;
669                                         }
670                                 }
671
672                                 return true;
673                         }
674                 }
675
676                 //
677                 // Checks whether two generic instances may become equal for some
678                 // particular instantiation (26.3.1).
679                 //
680                 public static class Unify
681                 {
682                         //
683                         // Either @a or @b must be generic type
684                         //
685                         public static bool IsEqual (TypeSpec a, TypeSpec b)
686                         {
687                                 if (a.MemberDefinition != b.MemberDefinition)
688                                         return false;
689
690                                 var ta = a.TypeArguments;
691                                 var tb = b.TypeArguments;
692                                 for (int i = 0; i < ta.Length; i++) {
693                                         if (!MayBecomeEqualGenericTypes (ta[i], tb[i]))
694                                                 return false;
695                                 }
696
697                                 return true;
698                         }
699
700                         static bool ContainsTypeParameter (TypeSpec tparam, TypeSpec type)
701                         {
702                                 TypeSpec[] targs = type.TypeArguments;
703                                 for (int i = 0; i < targs.Length; i++) {
704                                         if (tparam == targs[i])
705                                                 return true;
706
707                                         if (ContainsTypeParameter (tparam, targs[i]))
708                                                 return true;
709                                 }
710
711                                 return false;
712                         }
713
714                         /// <summary>
715                         ///   Check whether `a' and `b' may become equal generic types.
716                         ///   The algorithm to do that is a little bit complicated.
717                         /// </summary>
718                         static bool MayBecomeEqualGenericTypes (TypeSpec a, TypeSpec b)
719                         {
720                                 if (a.IsGenericParameter) {
721                                         //
722                                         // If a is an array of a's type, they may never
723                                         // become equal.
724                                         //
725                                         if (b.IsArray)
726                                                 return false;
727
728                                         //
729                                         // If b is a generic parameter or an actual type,
730                                         // they may become equal:
731                                         //
732                                         //    class X<T,U> : I<T>, I<U>
733                                         //    class X<T> : I<T>, I<float>
734                                         // 
735                                         if (b.IsGenericParameter)
736                                                 return a.DeclaringType == b.DeclaringType;
737
738                                         //
739                                         // We're now comparing a type parameter with a
740                                         // generic instance.  They may become equal unless
741                                         // the type parameter appears anywhere in the
742                                         // generic instance:
743                                         //
744                                         //    class X<T,U> : I<T>, I<X<U>>
745                                         //        -> error because you could instanciate it as
746                                         //           X<X<int>,int>
747                                         //
748                                         //    class X<T> : I<T>, I<X<T>> -> ok
749                                         //
750
751                                         return !ContainsTypeParameter (a, b);
752                                 }
753
754                                 if (b.IsGenericParameter)
755                                         return MayBecomeEqualGenericTypes (b, a);
756
757                                 //
758                                 // At this point, neither a nor b are a type parameter.
759                                 //
760                                 // If one of them is a generic instance, compare them (if the
761                                 // other one is not a generic instance, they can never
762                                 // become equal).
763                                 //
764                                 if (TypeManager.IsGenericType (a) || TypeManager.IsGenericType (b))
765                                         return IsEqual (a, b);
766
767                                 //
768                                 // If both of them are arrays.
769                                 //
770                                 var a_ac = a as ArrayContainer;
771                                 if (a_ac != null) {
772                                         var b_ac = b as ArrayContainer;
773                                         if (b_ac == null || a_ac.Rank != b_ac.Rank)
774                                                 return false;
775
776                                         return MayBecomeEqualGenericTypes (a_ac.Element, b_ac.Element);
777                                 }
778
779                                 //
780                                 // Ok, two ordinary types.
781                                 //
782                                 return false;
783                         }
784                 }
785
786                 public static bool Equals (TypeSpec[] x, TypeSpec[] y)
787                 {
788                         if (x == y)
789                                 return true;
790
791                         if (x.Length != y.Length)
792                                 return false;
793
794                         for (int i = 0; i < x.Length; ++i)
795                                 if (!IsEqual (x[i], y[i]))
796                                         return false;
797
798                         return true;
799                 }
800
801                 //
802                 // Identity type conversion
803                 //
804                 // Default reference comparison, it has to be used when comparing
805                 // two possible dynamic/internal types
806                 //
807                 public static bool IsEqual (TypeSpec a, TypeSpec b)
808                 {
809                         if (a == b) {
810                                 // This also rejects dynamic == dynamic
811                                 return a.Kind != MemberKind.InternalCompilerType || a == InternalType.Dynamic;
812                         }
813
814                         //
815                         // object and dynamic are considered equivalent there is an identity conversion
816                         // between object and dynamic, and between constructed types that are the same
817                         // when replacing all occurences of dynamic with object.
818                         //
819                         if (a == InternalType.Dynamic || b == InternalType.Dynamic)
820                                 return b == TypeManager.object_type || a == TypeManager.object_type;
821
822                         if (a == null)
823                                 return false;
824
825                         if (a.IsArray) {
826                                 var a_a = (ArrayContainer) a;
827                                 var b_a = b as ArrayContainer;
828                                 if (b_a == null)
829                                         return false;
830
831                                 return IsEqual (a_a.Element, b_a.Element) && a_a.Rank == b_a.Rank;
832                         }
833
834                         if (!a.IsGeneric || b == null || !b.IsGeneric)
835                                 return false;
836
837                         if (a.MemberDefinition != b.MemberDefinition)
838                                 return false;
839
840                         do {
841                                 if (!Equals (a.TypeArguments, b.TypeArguments))
842                                         return false;
843
844                                 a = a.DeclaringType;
845                                 b = b.DeclaringType;
846                         } while (a != null);
847
848                         return true;
849                 }
850         }
851
852         public interface ITypeDefinition : IMemberDefinition
853         {
854                 string Namespace { get; }
855                 int TypeParametersCount { get; }
856                 TypeParameterSpec[] TypeParameters { get; }
857
858                 TypeSpec GetAttributeCoClass ();
859                 string GetAttributeDefaultMember ();
860                 AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa);
861                 void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache);
862         }
863
864         class InternalType : TypeSpec
865         {
866                 public static readonly InternalType AnonymousMethod = new InternalType ("anonymous method");
867                 public static readonly InternalType Arglist = new InternalType ("__arglist");
868                 public static readonly InternalType Dynamic = new InternalType ("dynamic", null);
869                 public static readonly InternalType MethodGroup = new InternalType ("method group");
870                 public static readonly InternalType Null = new InternalType ("null");
871                 public static readonly InternalType FakeInternalType = new InternalType ("<fake$type>");
872
873                 readonly string name;
874
875                 InternalType (string name, MemberCache cache)
876                         : this (name)
877                 {
878                         this.cache = cache;
879                 }
880
881                 InternalType (string name)
882                         : base (MemberKind.InternalCompilerType, null, null, null, Modifiers.PUBLIC)
883                 {
884                         this.name = name;
885                         cache = MemberCache.Empty;
886
887                         // Make all internal types CLS-compliant, non-obsolete
888                         state = (state & ~(StateFlags.CLSCompliant_Undetected | StateFlags.Obsolete_Undetected)) | StateFlags.CLSCompliant;
889                 }
890
891                 #region Properties
892
893                 public override int Arity {
894                         get {
895                                 return 0;
896                         }
897                 }
898
899                 public override string Name {
900                         get {
901                                 return name;
902                         }
903                 }
904
905                 #endregion
906
907                 public override string GetSignatureForError ()
908                 {
909                         return name;
910                 }
911         }
912
913         public abstract class ElementTypeSpec : TypeSpec, ITypeDefinition
914         {
915                 protected ElementTypeSpec (MemberKind kind, TypeSpec element, Type info)
916                         : base (kind, element.DeclaringType, null, info, element.Modifiers)
917                 {
918                         this.Element = element;
919
920                         // Has to use its own type definition instead of just element definition to
921                         // correctly identify itself for cases like x.MemberDefininition == predefined.MemberDefinition
922                         this.definition = this;
923
924                         cache = MemberCache.Empty;
925                 }
926
927                 #region Properties
928
929                 public TypeSpec Element { get; private set; }
930
931                 public override string Name {
932                         get {
933                                 throw new NotSupportedException ();
934                         }
935                 }
936
937                 #endregion
938
939                 public override ObsoleteAttribute GetAttributeObsolete ()
940                 {
941                         return Element.GetAttributeObsolete ();
942                 }
943
944                 protected virtual string GetPostfixSignature ()
945                 {
946                         return null;
947                 }
948
949                 public override string GetSignatureForError ()
950                 {
951                         return Element.GetSignatureForError () + GetPostfixSignature ();
952                 }
953
954                 public override TypeSpec Mutate (TypeParameterMutator mutator)
955                 {
956                         var me = Element.Mutate (mutator);
957                         if (me == Element)
958                                 return this;
959
960                         var mutated = (ElementTypeSpec) MemberwiseClone ();
961                         mutated.Element = me;
962                         mutated.info = null;
963                         return mutated;
964                 }
965
966                 #region ITypeDefinition Members
967
968                 System.Reflection.Assembly IMemberDefinition.Assembly {
969                         get {
970                                 return Element.Assembly;
971                         }
972                 }
973
974                 public string Namespace {
975                         get { throw new NotImplementedException (); }
976                 }
977
978                 public int TypeParametersCount {
979                         get {
980                                 return 0;
981                         }
982                 }
983
984                 public TypeParameterSpec[] TypeParameters {
985                         get {
986                                 throw new NotSupportedException ();
987                         }
988                 }
989
990                 public TypeSpec GetAttributeCoClass ()
991                 {
992                         return Element.MemberDefinition.GetAttributeCoClass ();
993                 }
994
995                 public string GetAttributeDefaultMember ()
996                 {
997                         return Element.MemberDefinition.GetAttributeDefaultMember ();
998                 }
999
1000                 public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
1001                 {
1002                         Element.MemberDefinition.LoadMembers (declaringType, onlyTypes, ref cache);
1003                 }
1004
1005                 public bool IsImported {
1006                         get {
1007                                 return Element.MemberDefinition.IsImported;
1008                         }
1009                 }
1010
1011                 public string[] ConditionalConditions ()
1012                 {
1013                         return Element.MemberDefinition.ConditionalConditions ();
1014                 }
1015
1016                 bool IMemberDefinition.IsNotCLSCompliant ()
1017                 {
1018                         return Element.MemberDefinition.IsNotCLSCompliant ();
1019                 }
1020
1021                 public void SetIsAssigned ()
1022                 {
1023                         Element.MemberDefinition.SetIsAssigned ();
1024                 }
1025
1026                 public void SetIsUsed ()
1027                 {
1028                         Element.MemberDefinition.SetIsUsed ();
1029                 }
1030
1031                 #endregion
1032         }
1033
1034         public class ArrayContainer : ElementTypeSpec
1035         {
1036                 struct TypeRankPair : IEquatable<TypeRankPair>
1037                 {
1038                         TypeSpec ts;
1039                         int rank;
1040
1041                         public TypeRankPair (TypeSpec ts, int rank)
1042                         {
1043                                 this.ts = ts;
1044                                 this.rank = rank;
1045                         }
1046
1047                         public override int GetHashCode ()
1048                         {
1049                                 return ts.GetHashCode () ^ rank.GetHashCode ();
1050                         }
1051
1052                         #region IEquatable<Tuple<T1,T2>> Members
1053
1054                         public bool Equals (TypeRankPair other)
1055                         {
1056                                 return other.ts == ts && other.rank == rank;
1057                         }
1058
1059                         #endregion
1060                 }
1061
1062                 readonly int rank;
1063                 static Dictionary<TypeRankPair, ArrayContainer> instances = new Dictionary<TypeRankPair, ArrayContainer> ();
1064
1065                 private ArrayContainer (TypeSpec element, int rank)
1066                         : base (MemberKind.ArrayType, element, null)
1067                 {
1068                         this.rank = rank;
1069                 }
1070
1071                 public int Rank {
1072                         get {
1073                                 return rank;
1074                         }
1075                 }
1076
1077                 public System.Reflection.MethodInfo GetConstructor ()
1078                 {
1079                         var mb = RootContext.ToplevelTypes.Builder;
1080
1081                         var arg_types = new Type[rank];
1082                         for (int i = 0; i < rank; i++)
1083                                 arg_types[i] = TypeManager.int32_type.GetMetaInfo ();
1084
1085                         var ctor = mb.GetArrayMethod (
1086                                 GetMetaInfo (), ".ctor",
1087                                 System.Reflection.CallingConventions.HasThis,
1088                                 null, arg_types);
1089
1090                         return ctor;
1091                 }
1092
1093                 public System.Reflection.MethodInfo GetAddressMethod ()
1094                 {
1095                         var mb = RootContext.ToplevelTypes.Builder;
1096
1097                         var arg_types = new Type[rank];
1098                         for (int i = 0; i < rank; i++)
1099                                 arg_types[i] = TypeManager.int32_type.GetMetaInfo ();
1100
1101                         var address = mb.GetArrayMethod (
1102                                 GetMetaInfo (), "Address",
1103                                 System.Reflection.CallingConventions.HasThis | System.Reflection.CallingConventions.Standard,
1104                                 ReferenceContainer.MakeType (Element).GetMetaInfo (), arg_types);
1105
1106                         return address;
1107                 }
1108
1109                 public System.Reflection.MethodInfo GetGetMethod ()
1110                 {
1111                         var mb = RootContext.ToplevelTypes.Builder;
1112
1113                         var arg_types = new Type[rank];
1114                         for (int i = 0; i < rank; i++)
1115                                 arg_types[i] = TypeManager.int32_type.GetMetaInfo ();
1116
1117                         var get = mb.GetArrayMethod (
1118                                 GetMetaInfo (), "Get",
1119                                 System.Reflection.CallingConventions.HasThis | System.Reflection.CallingConventions.Standard,
1120                                 Element.GetMetaInfo (), arg_types);
1121
1122                         return get;
1123                 }
1124
1125                 public System.Reflection.MethodInfo GetSetMethod ()
1126                 {
1127                         var mb = RootContext.ToplevelTypes.Builder;
1128
1129                         var arg_types = new Type[rank + 1];
1130                         for (int i = 0; i < rank; i++)
1131                                 arg_types[i] = TypeManager.int32_type.GetMetaInfo ();
1132
1133                         arg_types[rank] = Element.GetMetaInfo ();
1134
1135                         var set = mb.GetArrayMethod (
1136                                 GetMetaInfo (), "Set",
1137                                 System.Reflection.CallingConventions.HasThis | System.Reflection.CallingConventions.Standard,
1138                                 TypeManager.void_type.GetMetaInfo (), arg_types);
1139
1140                         return set;
1141                 }
1142
1143                 public override Type GetMetaInfo ()
1144                 {
1145                         if (info == null) {
1146                                 if (rank == 1)
1147                                         info = Element.GetMetaInfo ().MakeArrayType ();
1148                                 else
1149                                         info = Element.GetMetaInfo ().MakeArrayType (rank);
1150                         }
1151
1152                         return info;
1153                 }
1154
1155                 protected override string GetPostfixSignature()
1156                 {
1157                         return GetPostfixSignature (rank);
1158                 }
1159
1160                 public static string GetPostfixSignature (int rank)
1161                 {
1162                         StringBuilder sb = new StringBuilder ();
1163                         sb.Append ("[");
1164                         for (int i = 1; i < rank; i++) {
1165                                 sb.Append (",");
1166                         }
1167                         sb.Append ("]");
1168
1169                         return sb.ToString ();
1170                 }
1171
1172                 public static ArrayContainer MakeType (TypeSpec element)
1173                 {
1174                         return MakeType (element, 1);
1175                 }
1176
1177                 public static ArrayContainer MakeType (TypeSpec element, int rank)
1178                 {
1179                         ArrayContainer ac;
1180                         var key = new TypeRankPair (element, rank);
1181                         if (!instances.TryGetValue (key, out ac)) {
1182                                 ac = new ArrayContainer (element, rank) {
1183                                         BaseType = TypeManager.array_type
1184                                 };
1185
1186                                 instances.Add (key, ac);
1187                         }
1188
1189                         return ac;
1190                 }
1191
1192                 public static void Reset ()
1193                 {
1194                         instances = new Dictionary<TypeRankPair, ArrayContainer> ();
1195                 }
1196         }
1197
1198         class ReferenceContainer : ElementTypeSpec
1199         {
1200                 static Dictionary<TypeSpec, ReferenceContainer> instances = new Dictionary<TypeSpec, ReferenceContainer> ();
1201
1202                 private ReferenceContainer (TypeSpec element)
1203                         : base (MemberKind.Class, element, null)        // TODO: Kind.Class is most likely wrong
1204                 {
1205                 }
1206
1207                 public override Type GetMetaInfo ()
1208                 {
1209                         if (info == null) {
1210                                 info = Element.GetMetaInfo ().MakeByRefType ();
1211                         }
1212
1213                         return info;
1214                 }
1215
1216                 public static ReferenceContainer MakeType (TypeSpec element)
1217                 {
1218                         ReferenceContainer pc;
1219                         if (!instances.TryGetValue (element, out pc)) {
1220                                 pc = new ReferenceContainer (element);
1221                                 instances.Add (element, pc);
1222                         }
1223
1224                         return pc;
1225                 }
1226
1227                 public static void Reset ()
1228                 {
1229                         instances = new Dictionary<TypeSpec, ReferenceContainer> ();
1230                 }
1231         }
1232
1233         class PointerContainer : ElementTypeSpec
1234         {
1235                 static Dictionary<TypeSpec, PointerContainer> instances = new Dictionary<TypeSpec, PointerContainer> ();
1236
1237                 private PointerContainer (TypeSpec element)
1238                         : base (MemberKind.PointerType, element, null)
1239                 {
1240                         // It's never CLS-Compliant
1241                         state &= ~StateFlags.CLSCompliant_Undetected;
1242                 }
1243
1244                 public override Type GetMetaInfo ()
1245                 {
1246                         if (info == null) {
1247                                 info = Element.GetMetaInfo ().MakePointerType ();
1248                         }
1249
1250                         return info;
1251                 }
1252
1253                 protected override string GetPostfixSignature()
1254                 {
1255                         return "*";
1256                 }
1257
1258                 public static PointerContainer MakeType (TypeSpec element)
1259                 {
1260                         PointerContainer pc;
1261                         if (!instances.TryGetValue (element, out pc)) {
1262                                 pc = new PointerContainer (element);
1263                                 instances.Add (element, pc);
1264                         }
1265
1266                         return pc;
1267                 }
1268
1269                 public static void Reset ()
1270                 {
1271                         instances = new Dictionary<TypeSpec, PointerContainer> ();
1272                 }
1273         }
1274 }