2010-05-20 Marek Safar <marek.safar@gmail.com>
[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 { return this is ArrayContainer; }
80                 }
81
82                 public bool IsAttribute {
83                         get {
84                                 if (!IsClass)
85                                         return false;
86
87                                 var type = this;
88                                 do {
89                                         if (type.IsGeneric)
90                                                 return false;
91
92                                         if (type == TypeManager.attribute_type)
93                                                 return true;
94                                         
95                                         type = type.base_type;
96                                 } while (type != null);
97
98                                 return false;
99                         }
100                 }
101
102                 public bool IsInterface {
103                         get {
104                                 return Kind == MemberKind.Interface;
105                         }
106                 }
107
108                 public bool IsClass {
109                         get {
110                                 return Kind == MemberKind.Class;
111                         }
112                 }
113
114                 public bool IsConstantCompatible {
115                         get {
116                                 if ((Kind & (MemberKind.Enum | MemberKind.Class | MemberKind.Interface | MemberKind.Delegate)) != 0)
117                                         return true;
118
119                                 return TypeManager.IsPrimitiveType (this) || this == TypeManager.decimal_type || this == InternalType.Dynamic;
120                         }
121                 }
122
123                 public bool IsDelegate {
124                         get {
125                                 return Kind == MemberKind.Delegate;
126                         }
127                 }
128
129                 public bool IsEnum {
130                         get { return Kind == MemberKind.Enum; }
131                 }
132
133                 // TODO: Should probably do
134                 // IsGenericType -- recursive
135                 // HasTypeParameter -- non-recursive
136                 public bool IsGenericOrParentIsGeneric {
137                         get {
138                                 var ts = this;
139                                 do {
140                                         if (ts.IsGeneric)
141                                                 return true;
142                                         ts = ts.declaringType;
143                                 } while (ts != null);
144
145                                 return false;
146                         }
147                 }
148
149                 public bool IsGenericParameter {
150                         get { return Kind == MemberKind.TypeParameter; }
151                 }
152
153                 public bool IsNested {
154                         get { return declaringType != null && Kind != MemberKind.TypeParameter; }
155                 }
156
157                 public bool IsPointer {
158                         get {
159                                 return Kind == MemberKind.PointerType;
160                         }
161                 }
162
163                 public bool IsSealed {
164                         get { return (Modifiers & Modifiers.SEALED) != 0; }
165                 }
166
167                 public bool IsStruct {
168                         get { 
169                                 return Kind == MemberKind.Struct;
170                         }
171                 }
172
173                 public bool IsTypeBuilder {
174                         get {
175                                 var meta = GetMetaInfo().GetType ();
176                                 return meta == TypeBuilder || meta == GenericTypeBuilder;
177                         }
178                 }
179
180                 public MemberCache MemberCache {
181                         get {
182                                 if (cache == null || (state & StateFlags.PendingMemberCacheMembers) != 0)
183                                         InitializeMemberCache (false);
184
185                                 return cache;
186                         }
187                         set {
188                                 if (cache != null)
189                                         throw new InternalErrorException ("Membercache reset");
190
191                                 cache = value;
192                         }
193                 }
194
195                 public virtual MemberCache MemberCacheTypes {
196                         get {
197                                 return MemberCache;
198                         }
199                 }       
200
201                 public new ITypeDefinition MemberDefinition {
202                         get {
203                                 return (ITypeDefinition) definition;
204                         }
205                 }
206
207                 // TODO: Wouldn't be better to rely on cast to InflatedTypeSpec and
208                 // remove the property, YES IT WOULD !!!
209                 public virtual TypeSpec[] TypeArguments {
210                         get { return TypeSpec.EmptyTypes; }
211                 }
212
213                 #endregion
214
215                 public bool AddInterface (TypeSpec iface)
216                 {
217                         if ((state & StateFlags.InterfacesExpanded) != 0)
218                                 throw new InternalErrorException ("Modifying expanded interface list");
219
220                         if (ifaces == null) {
221                                 ifaces = new List<TypeSpec> () { iface };
222                                 return true;
223                         }
224
225                         if (!ifaces.Contains (iface)) {
226                                 ifaces.Add (iface);
227                                 return true;
228                         }
229
230                         return false;
231                 }
232
233                 public AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa)
234                 {
235                         if (Kind != MemberKind.Class)
236                                 throw new InternalErrorException ();
237
238                         if (!pa.IsDefined)
239                                 return Attribute.DefaultUsageAttribute;
240
241                         AttributeUsageAttribute aua = null;
242                         var type = this;
243                         while (type != null) {
244                                 aua = type.MemberDefinition.GetAttributeUsage (pa);
245                                 if (aua != null)
246                                         break;
247
248                                 type = type.BaseType;
249                         }
250
251                         return aua;
252                 }
253
254                 public virtual Type GetMetaInfo ()
255                 {
256                         return info;
257                 }
258
259                 public virtual TypeSpec GetDefinition ()
260                 {
261                         return this;
262                 }
263
264                 public override string GetSignatureForError ()
265                 {
266                         string s;
267
268                         if (IsNested) {
269                                 s = DeclaringType.GetSignatureForError ();
270                         } else {
271                                 s = MemberDefinition.Namespace;
272                         }
273
274                         if (!string.IsNullOrEmpty (s))
275                                 s += ".";
276
277                         return s + Name + GetTypeNameSignature ();
278                 }
279
280                 protected virtual string GetTypeNameSignature ()
281                 {
282                         if (!IsGeneric)
283                                 return null;
284
285                         return "<" + TypeManager.CSharpName (MemberDefinition.TypeParameters) + ">";
286                 }
287
288                 public bool ImplementsInterface (TypeSpec iface)
289                 {
290                         var t = this;
291                         do {
292                                 if (t.Interfaces != null) {     // TODO: Try t.iface
293                                         foreach (TypeSpec i in t.Interfaces) {
294                                                 if (i == iface || TypeSpecComparer.Variant.IsEqual (i, iface))
295                                                         return true;
296                                         }
297                                 }
298
299                                 t = t.BaseType;
300                         } while (t != null);
301
302                         return false;
303                 }
304
305                 protected virtual void InitializeMemberCache (bool onlyTypes)
306                 {
307                         //
308                         // Not interested in members of nested private types
309                         //
310                         if (IsPrivate) {
311                                 cache = new MemberCache (0);
312                         } else {
313                                 cache = MemberDefinition.LoadMembers (this);
314                         }
315                 }
316
317                 public override MemberSpec InflateMember (TypeParameterInflator inflator)
318                 {
319                         var targs = IsGeneric ? MemberDefinition.TypeParameters : TypeSpec.EmptyTypes;
320
321                         //
322                         // When inflating nested type from inside the type instance will be same
323                         // because type parameters are same for all nested types
324                         //
325                         if (DeclaringType == inflator.TypeInstance)
326                                 return MakeGenericType (targs);
327
328                         return new InflatedTypeSpec (this, inflator.TypeInstance, targs);
329                 }
330
331                 public InflatedTypeSpec MakeGenericType (TypeSpec[] targs)
332                 {
333                         if (targs.Length == 0 && !IsNested)
334                                 throw new ArgumentException ("Empty type arguments");
335
336                         InflatedTypeSpec instance;
337
338                         if (inflated_instances == null)
339                                 inflated_instances = new Dictionary<TypeSpec[], InflatedTypeSpec> (TypeSpecComparer.Default);
340
341                         if (!inflated_instances.TryGetValue (targs, out instance)) {
342                                 if (GetDefinition () != this && !IsNested)
343                                         throw new InternalErrorException ("Only type definition or nested non-inflated types can be used to call MakeGenericType");
344
345                                 instance = new InflatedTypeSpec (this, declaringType, targs);
346                                 inflated_instances.Add (targs, instance);
347                         }
348
349                         return instance;
350                 }
351
352                 public virtual TypeSpec Mutate (TypeParameterMutator mutator)
353                 {
354                         return this;
355                 }
356
357                 public void SetMetaInfo (Type info)
358                 {
359                         if (this.info != null)
360                                 throw new InternalErrorException ("MetaInfo reset");
361
362                         this.info = info;
363                 }
364
365                 public void SetExtensionMethodContainer ()
366                 {
367                         modifiers |= Modifiers.METHOD_EXTENSION;
368                 }
369         }
370
371         public class PredefinedTypeSpec : TypeSpec
372         {
373                 string name;
374                 string ns;
375
376                 public PredefinedTypeSpec (MemberKind kind, string ns, string name)
377                         : base (kind, null, null, null, Modifiers.PUBLIC)
378                 {
379                         this.name = name;
380                         this.ns = ns;
381                 }
382
383                 public override int Arity {
384                         get {
385                                 return 0;
386                         }
387                 }
388
389                 public override string Name {
390                         get {
391                                 return name;
392                         }
393                 }
394
395                 public string Namespace {
396                         get {
397                                 return ns;
398                         }
399                 }
400
401                 public override string GetSignatureForError ()
402                 {
403                         switch (name) {
404                         case "Int32": return "int";
405                         case "Int64": return "long";
406                         case "String": return "string";
407                         case "Boolean": return "bool";
408                         case "Void": return "void";
409                         case "Object": return "object";
410                         case "UInt32": return "uint";
411                         case "Int16": return "short";
412                         case "UInt16": return "ushort";
413                         case "UInt64": return "ulong";
414                         case "Single": return "float";
415                         case "Double": return "double";
416                         case "Decimal": return "decimal";
417                         case "Char": return "char";
418                         case "Byte": return "byte";
419                         case "SByte": return "sbyte";
420                         }
421
422                         return ns + "." + name;
423                 }
424
425                 public void SetDefinition (ITypeDefinition td, Type type)
426                 {
427                         this.definition = td;
428                         this.info = type;
429                 }
430
431                 public void SetDefinition (TypeSpec ts)
432                 {
433                         this.definition = ts.MemberDefinition;
434                         this.info = ts.GetMetaInfo ();
435                         this.BaseType = ts.BaseType;
436                         this.Interfaces = ts.Interfaces;
437                 }
438         }
439
440         static class TypeSpecComparer
441         {
442                 //
443                 // Default reference comparison
444                 //
445                 public static readonly DefaultImpl Default = new DefaultImpl ();
446
447                 public class DefaultImpl : IEqualityComparer<TypeSpec[]>, IEqualityComparer<Tuple<TypeSpec, TypeSpec[]>>
448                 {
449                         #region IEqualityComparer<TypeSpec[]> Members
450
451                         public bool Equals (TypeSpec[] x, TypeSpec[] y)
452                         {
453                                 if (x.Length != y.Length)
454                                         return false;
455
456                                 if (x == y)
457                                         return true;
458
459                                 for (int i = 0; i < x.Length; ++i)
460                                         if (x[i] != y[i])
461                                                 return false;
462
463                                 return true;
464                         }
465
466                         public int GetHashCode (TypeSpec[] obj)
467                         {
468                                 int hash = 0;
469                                 for (int i = 0; i < obj.Length; ++i)
470                                         hash = (hash << 5) - hash + obj[i].GetHashCode ();
471
472                                 return hash;
473                         }
474
475                         #endregion
476
477                         #region IEqualityComparer<Tuple<TypeSpec,TypeSpec[]>> Members
478
479                         bool IEqualityComparer<Tuple<TypeSpec, TypeSpec[]>>.Equals (Tuple<TypeSpec, TypeSpec[]> x, Tuple<TypeSpec, TypeSpec[]> y)
480                         {
481                                 return Equals (x.Item2, y.Item2) && x.Item1 == y.Item1;
482                         }
483
484                         int IEqualityComparer<Tuple<TypeSpec, TypeSpec[]>>.GetHashCode (Tuple<TypeSpec, TypeSpec[]> obj)
485                         {
486                                 return GetHashCode (obj.Item2) ^ obj.Item1.GetHashCode ();
487                         }
488
489                         #endregion
490                 }
491
492                 //
493                 // When comparing type signature of overrides or overloads
494                 // this version tolerates different MVARs at same position
495                 //
496                 public static class Override
497                 {
498                         public static bool IsEqual (TypeSpec a, TypeSpec b)
499                         {
500                                 if (a == b)
501                                         return true;
502
503                                 //
504                                 // Consider the following example:
505                                 //
506                                 //     public abstract class A
507                                 //     {
508                                 //        public abstract T Foo<T>();
509                                 //     }
510                                 //
511                                 //     public class B : A
512                                 //     {
513                                 //        public override U Foo<T>() { return default (U); }
514                                 //     }
515                                 //
516                                 // Here, `T' and `U' are method type parameters from different methods
517                                 // (A.Foo and B.Foo), so both `==' and Equals() will fail.
518                                 //
519                                 // However, since we're determining whether B.Foo() overrides A.Foo(),
520                                 // we need to do a signature based comparision and consider them equal.
521                                 //
522
523                                 var tp_a = a as TypeParameterSpec;
524                                 if (tp_a != null) {
525                                         var tp_b = b as TypeParameterSpec;
526                                         return tp_b != null && tp_a.IsMethodOwned == tp_b.IsMethodOwned && tp_a.DeclaredPosition == tp_b.DeclaredPosition;
527                                 }
528
529                                 if (a.TypeArguments.Length != b.TypeArguments.Length)
530                                         return false;
531
532                                 if (a.TypeArguments.Length != 0) {
533                                         if (a.MemberDefinition != b.MemberDefinition)
534                                                 return false;
535
536                                         for (int i = 0; i < a.TypeArguments.Length; ++i) {
537                                                 if (!IsEqual (a.TypeArguments[i], b.TypeArguments[i]))
538                                                         return false;
539                                         }
540
541                                         return true;
542                                 }
543
544                                 var ac_a = a as ArrayContainer;
545                                 if (ac_a != null) {
546                                         var ac_b = b as ArrayContainer;
547                                         return ac_b != null && ac_a.Rank == ac_b.Rank && IsEqual (ac_a.Element, ac_b.Element);
548                                 }
549
550                                 if (a == InternalType.Dynamic || b == InternalType.Dynamic)
551                                         return b == TypeManager.object_type || a == TypeManager.object_type;
552
553                                 return false;
554                         }
555
556                         //
557                         // Compares unordered arrays
558                         //
559                         public static bool IsSame (TypeSpec[] a, TypeSpec[] b)
560                         {
561                                 if (a == b)
562                                         return true;
563
564                                 if (a == null || b == null || a.Length != b.Length)
565                                         return false;
566
567                                 for (int ai = 0; ai < a.Length; ++ai) {
568                                         bool found = false;
569                                         for (int bi = 0; bi < b.Length; ++bi) {
570                                                 if (IsEqual (a[ai], b[bi])) {
571                                                         found = true;
572                                                         break;
573                                                 }
574                                         }
575
576                                         if (!found)
577                                                 return false;
578                                 }
579
580                                 return true;
581                         }
582
583                         public static bool IsEqual (AParametersCollection a, AParametersCollection b)
584                         {
585                                 if (a == b)
586                                         return true;
587
588                                 if (a.Count != b.Count)
589                                         return false;
590
591                                 for (int i = 0; i < a.Count; ++i) {
592                                         if (!IsEqual (a.Types[i], b.Types[i]))
593                                                 return false;
594
595                                         const Parameter.Modifier ref_out = Parameter.Modifier.REF | Parameter.Modifier.OUT;
596                                         if ((a.FixedParameters[i].ModFlags & ref_out) != (b.FixedParameters[i].ModFlags & ref_out))
597                                                 return false;
598                                 }
599
600                                 return true;
601                         }
602                 }
603
604                 //
605                 // Type variance equality comparison
606                 //
607                 public static class Variant
608                 {
609                         public static bool IsEqual (TypeSpec type1, TypeSpec type2)
610                         {
611                                 if (!type1.IsGeneric || !type2.IsGeneric)
612                                         return false;
613
614                                 var target_type_def = type2.MemberDefinition;
615                                 if (type1.MemberDefinition != target_type_def)
616                                         return false;
617
618                                 if (!type1.IsInterface && !type1.IsDelegate)
619                                         return false;
620
621                                 var t1_targs = type1.TypeArguments;
622                                 var t2_targs = type2.TypeArguments;
623                                 var targs_definition = target_type_def.TypeParameters;
624                                 for (int i = 0; i < targs_definition.Length; ++i) {
625                                         Variance v = targs_definition[i].Variance;
626                                         if (v == Variance.None) {
627                                                 if (t1_targs[i] == t2_targs[i])
628                                                         continue;
629                                                 return false;
630                                         }
631
632                                         if (v == Variance.Covariant) {
633                                                 if (!Convert.ImplicitReferenceConversionExists (new EmptyExpression (t1_targs[i]), t2_targs[i]))
634                                                         return false;
635                                         } else if (!Convert.ImplicitReferenceConversionExists (new EmptyExpression (t2_targs[i]), t1_targs[i])) {
636                                                 return false;
637                                         }
638                                 }
639
640                                 return true;
641                         }
642                 }
643
644                 //
645                 // Checks whether two generic instances may become equal for some
646                 // particular instantiation (26.3.1).
647                 //
648                 public static class Unify
649                 {
650                         //
651                         // Either @a or @b must be generic type
652                         //
653                         public static bool IsEqual (TypeSpec a, TypeSpec b)
654                         {
655                                 if (a.MemberDefinition != b.MemberDefinition)
656                                         return false;
657
658                                 var ta = a.TypeArguments;
659                                 var tb = b.TypeArguments;
660                                 for (int i = 0; i < ta.Length; i++) {
661                                         if (!MayBecomeEqualGenericTypes (ta[i], tb[i]))
662                                                 return false;
663                                 }
664
665                                 return true;
666                         }
667
668                         static bool ContainsTypeParameter (TypeSpec tparam, TypeSpec type)
669                         {
670                                 TypeSpec[] targs = type.TypeArguments;
671                                 for (int i = 0; i < targs.Length; i++) {
672                                         if (tparam == targs[i])
673                                                 return true;
674
675                                         if (ContainsTypeParameter (tparam, targs[i]))
676                                                 return true;
677                                 }
678
679                                 return false;
680                         }
681
682                         /// <summary>
683                         ///   Check whether `a' and `b' may become equal generic types.
684                         ///   The algorithm to do that is a little bit complicated.
685                         /// </summary>
686                         static bool MayBecomeEqualGenericTypes (TypeSpec a, TypeSpec b)
687                         {
688                                 if (a.IsGenericParameter) {
689                                         //
690                                         // If a is an array of a's type, they may never
691                                         // become equal.
692                                         //
693                                         if (b.IsArray)
694                                                 return false;
695
696                                         //
697                                         // If b is a generic parameter or an actual type,
698                                         // they may become equal:
699                                         //
700                                         //    class X<T,U> : I<T>, I<U>
701                                         //    class X<T> : I<T>, I<float>
702                                         // 
703                                         if (b.IsGenericParameter)
704                                                 return a.DeclaringType == b.DeclaringType;
705
706                                         //
707                                         // We're now comparing a type parameter with a
708                                         // generic instance.  They may become equal unless
709                                         // the type parameter appears anywhere in the
710                                         // generic instance:
711                                         //
712                                         //    class X<T,U> : I<T>, I<X<U>>
713                                         //        -> error because you could instanciate it as
714                                         //           X<X<int>,int>
715                                         //
716                                         //    class X<T> : I<T>, I<X<T>> -> ok
717                                         //
718
719                                         return !ContainsTypeParameter (a, b);
720                                 }
721
722                                 if (b.IsGenericParameter)
723                                         return MayBecomeEqualGenericTypes (b, a);
724
725                                 //
726                                 // At this point, neither a nor b are a type parameter.
727                                 //
728                                 // If one of them is a generic instance, compare them (if the
729                                 // other one is not a generic instance, they can never
730                                 // become equal).
731                                 //
732                                 if (TypeManager.IsGenericType (a) || TypeManager.IsGenericType (b))
733                                         return IsEqual (a, b);
734
735                                 //
736                                 // If both of them are arrays.
737                                 //
738                                 var a_ac = a as ArrayContainer;
739                                 if (a_ac != null) {
740                                         var b_ac = b as ArrayContainer;
741                                         if (b_ac == null || a_ac.Rank != b_ac.Rank)
742                                                 return false;
743
744                                         return MayBecomeEqualGenericTypes (a_ac.Element, b_ac.Element);
745                                 }
746
747                                 //
748                                 // Ok, two ordinary types.
749                                 //
750                                 return false;
751                         }
752                 }
753         }
754
755         public interface ITypeDefinition : IMemberDefinition
756         {
757                 string Namespace { get; }
758                 int TypeParametersCount { get; }
759                 TypeParameterSpec[] TypeParameters { get; }
760
761                 TypeSpec GetAttributeCoClass ();
762                 string GetAttributeDefaultMember ();
763                 AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa);
764                 MemberCache LoadMembers (TypeSpec declaringType);
765         }
766
767         class InternalType : TypeSpec
768         {
769                 private class DynamicType : InternalType
770                 {
771                         public DynamicType ()
772                                 : base ("dynamic")
773                         {
774                         }
775
776                         public override Type GetMetaInfo ()
777                         {
778                                 return typeof (object);
779                         }
780                 }
781
782                 public static readonly TypeSpec AnonymousMethod = new InternalType ("anonymous method");
783                 public static readonly TypeSpec Arglist = new InternalType ("__arglist");
784                 public static readonly TypeSpec Dynamic = new DynamicType ();
785                 public static readonly TypeSpec MethodGroup = new InternalType ("method group");
786                 public static readonly TypeSpec Null = new InternalType ("null");
787                 public static readonly TypeSpec FakeInternalType = new InternalType ("<fake$type>");
788
789                 readonly string name;
790
791                 protected InternalType (string name)
792                         : base (MemberKind.InternalCompilerType, null, null, null, Modifiers.PUBLIC)
793                 {
794                         this.name = name;
795                         cache = MemberCache.Empty;
796
797                         // Make all internal types CLS-compliant, non-obsolete
798                         state = (state & ~(StateFlags.CLSCompliant_Undetected | StateFlags.Obsolete_Undetected)) | StateFlags.CLSCompliant;
799                 }
800
801                 public override string Name {
802                         get {
803                                 return name;
804                         }
805                 }
806
807                 public override string GetSignatureForError ()
808                 {
809                         return name;
810                 }
811         }
812
813         public abstract class ElementTypeSpec : TypeSpec
814         {
815                 protected ElementTypeSpec (MemberKind kind, TypeSpec element, Type info)
816                         : base (kind, element.DeclaringType, element.MemberDefinition, info, element.Modifiers)
817                 {
818                         this.Element = element;
819                         cache = MemberCache.Empty;
820                 }
821
822                 #region Properties
823
824                 public TypeSpec Element { get; private set; }
825
826                 public override string Name {
827                         get {
828                                 throw new NotSupportedException ();
829                         }
830                 }
831
832                 #endregion
833
834                 public override ObsoleteAttribute GetAttributeObsolete ()
835                 {
836                         return Element.GetAttributeObsolete ();
837                 }
838
839                 protected virtual string GetPostfixSignature ()
840                 {
841                         return null;
842                 }
843
844                 public override string GetSignatureForError ()
845                 {
846                         return Element.GetSignatureForError () + GetPostfixSignature ();
847                 }
848
849                 public override TypeSpec Mutate (TypeParameterMutator mutator)
850                 {
851                         var me = Element.Mutate (mutator);
852                         if (me == Element)
853                                 return this;
854
855                         var mutated = (ElementTypeSpec) MemberwiseClone ();
856                         mutated.Element = me;
857                         mutated.info = null;
858                         return mutated;
859                 }
860         }
861
862         public class ArrayContainer : ElementTypeSpec
863         {
864                 readonly int rank;
865                 static Dictionary<Tuple<TypeSpec, int>, ArrayContainer> instances = new Dictionary<Tuple<TypeSpec, int>, ArrayContainer> ();
866
867                 private ArrayContainer (TypeSpec element, int rank)
868                         : base (MemberKind.Class, element, null)
869                 {
870                         this.rank = rank;
871                 }
872
873                 public int Rank {
874                         get {
875                                 return rank;
876                         }
877                 }
878
879                 public System.Reflection.MethodInfo GetConstructor ()
880                 {
881                         var mb = RootContext.ToplevelTypes.Builder;
882
883                         var arg_types = new Type[rank];
884                         for (int i = 0; i < rank; i++)
885                                 arg_types[i] = TypeManager.int32_type.GetMetaInfo ();
886
887                         var ctor = mb.GetArrayMethod (
888                                 GetMetaInfo (), ".ctor",
889                                 System.Reflection.CallingConventions.HasThis,
890                                 null, arg_types);
891
892                         return ctor;
893                 }
894
895                 public System.Reflection.MethodInfo GetAddressMethod ()
896                 {
897                         var mb = RootContext.ToplevelTypes.Builder;
898
899                         var arg_types = new Type[rank];
900                         for (int i = 0; i < rank; i++)
901                                 arg_types[i] = TypeManager.int32_type.GetMetaInfo ();
902
903                         var address = mb.GetArrayMethod (
904                                 GetMetaInfo (), "Address",
905                                 System.Reflection.CallingConventions.HasThis | System.Reflection.CallingConventions.Standard,
906                                 ReferenceContainer.MakeType (Element).GetMetaInfo (), arg_types);
907
908                         return address;
909                 }
910
911                 public System.Reflection.MethodInfo GetGetMethod ()
912                 {
913                         var mb = RootContext.ToplevelTypes.Builder;
914
915                         var arg_types = new Type[rank];
916                         for (int i = 0; i < rank; i++)
917                                 arg_types[i] = TypeManager.int32_type.GetMetaInfo ();
918
919                         var get = mb.GetArrayMethod (
920                                 GetMetaInfo (), "Get",
921                                 System.Reflection.CallingConventions.HasThis | System.Reflection.CallingConventions.Standard,
922                                 Element.GetMetaInfo (), arg_types);
923
924                         return get;
925                 }
926
927                 public System.Reflection.MethodInfo GetSetMethod ()
928                 {
929                         var mb = RootContext.ToplevelTypes.Builder;
930
931                         var arg_types = new Type[rank + 1];
932                         for (int i = 0; i < rank; i++)
933                                 arg_types[i] = TypeManager.int32_type.GetMetaInfo ();
934
935                         arg_types[rank] = Element.GetMetaInfo ();
936
937                         var set = mb.GetArrayMethod (
938                                 GetMetaInfo (), "Set",
939                                 System.Reflection.CallingConventions.HasThis | System.Reflection.CallingConventions.Standard,
940                                 TypeManager.void_type.GetMetaInfo (), arg_types);
941
942                         return set;
943                 }
944
945                 public override Type GetMetaInfo ()
946                 {
947                         if (info == null) {
948                                 if (rank == 1)
949                                         info = Element.GetMetaInfo ().MakeArrayType ();
950                                 else
951                                         info = Element.GetMetaInfo ().MakeArrayType (rank);
952                         }
953
954                         return info;
955                 }
956
957                 protected override string GetPostfixSignature()
958                 {
959                         StringBuilder sb = new StringBuilder ();
960                         sb.Append ("[");
961                         for (int i = 1; i < rank; i++) {
962                                 sb.Append (",");
963                         }
964                         sb.Append ("]");
965
966                         return sb.ToString ();
967                 }
968
969                 public static ArrayContainer MakeType (TypeSpec element)
970                 {
971                         return MakeType (element, 1);
972                 }
973
974                 public static ArrayContainer MakeType (TypeSpec element, int rank)
975                 {
976                         ArrayContainer ac;
977                         var key = Tuple.Create (element, rank);
978                         if (!instances.TryGetValue (key, out ac)) {
979                                 ac = new ArrayContainer (element, rank) {
980                                         BaseType = TypeManager.array_type
981                                 };
982
983                                 instances.Add (key, ac);
984                         }
985
986                         return ac;
987                 }
988
989                 public static void Reset ()
990                 {
991                         instances = new Dictionary<Tuple<TypeSpec, int>, ArrayContainer> ();
992                 }
993         }
994
995         class ReferenceContainer : ElementTypeSpec
996         {
997                 static Dictionary<TypeSpec, ReferenceContainer> instances = new Dictionary<TypeSpec, ReferenceContainer> ();
998
999                 private ReferenceContainer (TypeSpec element)
1000                         : base (MemberKind.Class, element, null)        // TODO: Kind.Class is most likely wrong
1001                 {
1002                 }
1003
1004                 public override Type GetMetaInfo ()
1005                 {
1006                         if (info == null) {
1007                                 info = Element.GetMetaInfo ().MakeByRefType ();
1008                         }
1009
1010                         return info;
1011                 }
1012
1013                 public static ReferenceContainer MakeType (TypeSpec element)
1014                 {
1015                         ReferenceContainer pc;
1016                         if (!instances.TryGetValue (element, out pc)) {
1017                                 pc = new ReferenceContainer (element);
1018                                 instances.Add (element, pc);
1019                         }
1020
1021                         return pc;
1022                 }
1023
1024                 public static void Reset ()
1025                 {
1026                         instances = new Dictionary<TypeSpec, ReferenceContainer> ();
1027                 }
1028         }
1029
1030         class PointerContainer : ElementTypeSpec
1031         {
1032                 static Dictionary<TypeSpec, PointerContainer> instances = new Dictionary<TypeSpec, PointerContainer> ();
1033
1034                 private PointerContainer (TypeSpec element)
1035                         : base (MemberKind.PointerType, element, null)
1036                 {
1037                         // It's never CLS-Compliant
1038                         state &= ~StateFlags.CLSCompliant_Undetected;
1039                 }
1040
1041                 public override Type GetMetaInfo ()
1042                 {
1043                         if (info == null) {
1044                                 info = Element.GetMetaInfo ().MakePointerType ();
1045                         }
1046
1047                         return info;
1048                 }
1049
1050                 protected override string GetPostfixSignature()
1051                 {
1052                         return "*";
1053                 }
1054
1055                 public static PointerContainer MakeType (TypeSpec element)
1056                 {
1057                         PointerContainer pc;
1058                         if (!instances.TryGetValue (element, out pc)) {
1059                                 pc = new PointerContainer (element);
1060                                 instances.Add (element, pc);
1061                         }
1062
1063                         return pc;
1064                 }
1065
1066                 public static void Reset ()
1067                 {
1068                         instances = new Dictionary<TypeSpec, PointerContainer> ();
1069                 }
1070         }
1071 }