Check for identical override when implementing generic interface
[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
15 #if STATIC
16 using MetaType = IKVM.Reflection.Type;
17 using IKVM.Reflection;
18 #else
19 using MetaType = System.Type;
20 using System.Reflection;
21 #endif
22
23 namespace Mono.CSharp
24 {
25         public class TypeSpec : MemberSpec
26         {
27                 protected MetaType info;
28                 protected MemberCache cache;
29                 protected IList<TypeSpec> ifaces;
30                 TypeSpec base_type;
31
32                 Dictionary<TypeSpec[], InflatedTypeSpec> inflated_instances;
33
34                 public static readonly TypeSpec[] EmptyTypes = new TypeSpec[0];
35
36 #if !STATIC
37                 // Reflection Emit hacking
38                 static readonly Type TypeBuilder;
39                 static readonly Type GenericTypeBuilder;
40
41                 static TypeSpec ()
42                 {
43                         var assembly = typeof (object).Assembly;
44                         TypeBuilder = assembly.GetType ("System.Reflection.Emit.TypeBuilder");
45                         GenericTypeBuilder = assembly.GetType ("System.Reflection.MonoGenericClass");
46                         if (GenericTypeBuilder == null)
47                                 GenericTypeBuilder = assembly.GetType ("System.Reflection.Emit.TypeBuilderInstantiation");
48                 }
49 #endif
50
51                 public TypeSpec (MemberKind kind, TypeSpec declaringType, ITypeDefinition definition, MetaType info, Modifiers modifiers)
52                         : base (kind, declaringType, definition, modifiers)
53                 {
54                         this.declaringType = declaringType;
55                         this.info = info;
56
57                         if (definition != null && definition.TypeParametersCount > 0)
58                                 state |= StateFlags.IsGeneric;
59                 }
60
61                 #region Properties
62
63                 public override int Arity {
64                         get {
65                                 return MemberDefinition.TypeParametersCount;
66                         }
67                 }
68
69                 public virtual TypeSpec BaseType {
70                         get {
71                                 return base_type;
72                         }
73                         set {
74                                 base_type = value;
75                         }
76                 }
77
78                 public virtual BuiltinTypeSpec.Type BuiltinType {
79                         get {
80                                 return BuiltinTypeSpec.Type.None;
81                         }
82                 }
83
84                 public bool HasDynamicElement {
85                         get {
86                                 return (state & StateFlags.HasDynamicElement) != 0;
87                         }
88                 }
89
90                 public virtual IList<TypeSpec> Interfaces {
91                         get {
92                                 return ifaces;
93                         }
94                         set {
95                                 ifaces = value;
96                         }
97                 }
98
99                 public bool IsArray {
100                         get {
101                                 return Kind == MemberKind.ArrayType;
102                         }
103                 }
104
105                 public bool IsAttribute {
106                         get {
107                                 if (!IsClass)
108                                         return false;
109
110                                 var type = this;
111                                 do {
112                                         if (type.BuiltinType == BuiltinTypeSpec.Type.Attribute)
113                                                 return true;
114
115                                         if (type.IsGeneric)
116                                                 return false;
117                                         
118                                         type = type.base_type;
119                                 } while (type != null);
120
121                                 return false;
122                         }
123                 }
124
125                 public bool IsInterface {
126                         get {
127                                 return Kind == MemberKind.Interface;
128                         }
129                 }
130
131                 public bool IsClass {
132                         get {
133                                 return Kind == MemberKind.Class;
134                         }
135                 }
136
137                 public bool IsConstantCompatible {
138                         get {
139                                 if ((Kind & (MemberKind.Enum | MemberKind.Class | MemberKind.Interface | MemberKind.Delegate | MemberKind.ArrayType)) != 0)
140                                         return true;
141
142                                 switch (BuiltinType) {
143                                 case BuiltinTypeSpec.Type.Int:
144                                 case BuiltinTypeSpec.Type.UInt:
145                                 case BuiltinTypeSpec.Type.Long:
146                                 case BuiltinTypeSpec.Type.ULong:
147                                 case BuiltinTypeSpec.Type.Float:
148                                 case BuiltinTypeSpec.Type.Double:
149                                 case BuiltinTypeSpec.Type.Char:
150                                 case BuiltinTypeSpec.Type.Short:
151                                 case BuiltinTypeSpec.Type.Decimal:
152                                 case BuiltinTypeSpec.Type.Bool:
153                                 case BuiltinTypeSpec.Type.SByte:
154                                 case BuiltinTypeSpec.Type.Byte:
155                                 case BuiltinTypeSpec.Type.UShort:
156                                 case BuiltinTypeSpec.Type.Dynamic:
157                                         return true;
158                                 }
159
160                                 return false;
161                         }
162                 }
163
164                 public bool IsDelegate {
165                         get {
166                                 return Kind == MemberKind.Delegate;
167                         }
168                 }
169
170                 //
171                 // Returns true for instances of Expression<T>
172                 //
173                 public virtual bool IsExpressionTreeType {
174                         get {
175                                 return false;
176                         }
177                         set {
178                                 state = value ? state | StateFlags.InflatedExpressionType : state & ~StateFlags.InflatedExpressionType;
179                         }
180                 }
181
182                 public bool IsEnum {
183                         get {
184                                 return Kind == MemberKind.Enum;
185                         }
186                 }
187
188                 //
189                 // Returns true for instances of IList<T>, IEnumerable<T>, ICollection<T>
190                 //
191                 public virtual bool IsGenericIterateInterface {
192                         get {
193                                 return false;
194                         }
195                         set {
196                                 state = value ? state | StateFlags.GenericIterateInterface : state & ~StateFlags.GenericIterateInterface;
197                         }
198                 }
199
200                 // TODO: Should probably do
201                 // IsGenericType -- recursive
202                 // HasTypeParameter -- non-recursive
203                 public bool IsGenericOrParentIsGeneric {
204                         get {
205                                 var ts = this;
206                                 do {
207                                         if (ts.IsGeneric)
208                                                 return true;
209                                         ts = ts.declaringType;
210                                 } while (ts != null);
211
212                                 return false;
213                         }
214                 }
215
216                 public bool IsGenericParameter {
217                         get {
218                                 return Kind == MemberKind.TypeParameter;
219                         }
220                 }
221
222                 //
223                 // Returns true for instances of Nullable<T>
224                 //
225                 public virtual bool IsNullableType {
226                         get {
227                                 return false;
228                         }
229                         set {
230                                 state = value ? state | StateFlags.InflatedNullableType : state & ~StateFlags.InflatedNullableType;
231                         }
232                 }
233
234                 public bool IsNested {
235                         get { return declaringType != null && Kind != MemberKind.TypeParameter; }
236                 }
237
238                 public bool IsPointer {
239                         get {
240                                 return Kind == MemberKind.PointerType;
241                         }
242                 }
243
244                 public bool IsSealed {
245                         get { return (Modifiers & Modifiers.SEALED) != 0; }
246                 }
247
248                 public bool IsSpecialRuntimeType {
249                         get {
250                                 return (state & StateFlags.SpecialRuntimeType) != 0;
251                         }
252                         set {
253                                 state = value ? state | StateFlags.SpecialRuntimeType : state & ~StateFlags.SpecialRuntimeType;
254                         }
255                 }
256
257                 public bool IsStruct {
258                         get { 
259                                 return Kind == MemberKind.Struct;
260                         }
261                 }
262
263                 public bool IsTypeBuilder {
264                         get {
265 #if STATIC
266                                 return true;
267 #else
268                                 var meta = GetMetaInfo().GetType ();
269                                 return meta == TypeBuilder || meta == GenericTypeBuilder;
270 #endif
271                         }
272                 }
273
274                 public MemberCache MemberCache {
275                         get {
276                                 if (cache == null || (state & StateFlags.PendingMemberCacheMembers) != 0)
277                                         InitializeMemberCache (false);
278
279                                 return cache;
280                         }
281                         set {
282                                 if (cache != null)
283                                         throw new InternalErrorException ("Membercache reset");
284
285                                 cache = value;
286                         }
287                 }
288
289                 public MemberCache MemberCacheTypes {
290                         get {
291                                 if (cache == null)
292                                         InitializeMemberCache (true);
293
294                                 return cache;
295                         }
296                 }       
297
298                 public new ITypeDefinition MemberDefinition {
299                         get {
300                                 return (ITypeDefinition) definition;
301                         }
302                 }
303
304                 // TODO: Wouldn't be better to rely on cast to InflatedTypeSpec and
305                 // remove the property, YES IT WOULD !!!
306                 public virtual TypeSpec[] TypeArguments {
307                         get { return TypeSpec.EmptyTypes; }
308                 }
309
310                 #endregion
311
312                 public bool AddInterface (TypeSpec iface)
313                 {
314                         if ((state & StateFlags.InterfacesExpanded) != 0)
315                                 throw new InternalErrorException ("Modifying expanded interface list");
316
317                         if (ifaces == null) {
318                                 ifaces = new List<TypeSpec> () { iface };
319                                 return true;
320                         }
321
322                         if (!ifaces.Contains (iface)) {
323                                 ifaces.Add (iface);
324                                 return true;
325                         }
326
327                         return false;
328                 }
329
330                 public AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa)
331                 {
332                         if (Kind != MemberKind.Class)
333                                 throw new InternalErrorException ();
334
335                         if (!pa.IsDefined)
336                                 return Attribute.DefaultUsageAttribute;
337
338                         AttributeUsageAttribute aua = null;
339                         var type = this;
340                         while (type != null) {
341                                 aua = type.MemberDefinition.GetAttributeUsage (pa);
342                                 if (aua != null)
343                                         break;
344
345                                 type = type.BaseType;
346                         }
347
348                         return aua;
349                 }
350
351                 public virtual MetaType GetMetaInfo ()
352                 {
353                         return info;
354                 }
355
356                 public virtual TypeSpec GetDefinition ()
357                 {
358                         return this;
359                 }
360
361                 public override string GetSignatureForDocumentation ()
362                 {
363                         StringBuilder sb = new StringBuilder ();
364                         if (IsNested) {
365                                 sb.Append (DeclaringType.GetSignatureForDocumentation ());
366                         } else {
367                                 sb.Append (MemberDefinition.Namespace);
368                         }
369
370                         if (sb.Length != 0)
371                                 sb.Append (".");
372
373                         sb.Append (Name);
374                         if (Arity > 0) {
375                                 if (this is InflatedTypeSpec) {
376                                     sb.Append ("{");
377                                     for (int i = 0; i < Arity; ++i) {
378                                         if (i > 0)
379                                             sb.Append (",");
380
381                                         sb.Append (TypeArguments[i].GetSignatureForDocumentation ());
382                                     }
383                                     sb.Append ("}");
384                                 } else {
385                                         sb.Append ("`");
386                                         sb.Append (Arity.ToString ());
387                                 }
388                         }
389
390                         return sb.ToString ();
391                 }
392
393                 public string GetExplicitNameSignatureForDocumentation ()
394                 {
395                         StringBuilder sb = new StringBuilder ();
396                         if (IsNested) {
397                                 sb.Append (DeclaringType.GetExplicitNameSignatureForDocumentation ());
398                         } else if (MemberDefinition.Namespace != null) {
399                                 sb.Append (MemberDefinition.Namespace.Replace ('.', '#'));
400                         }
401
402                         if (sb.Length != 0)
403                                 sb.Append ("#");
404
405                         sb.Append (Name);
406                         if (Arity > 0) {
407                                 sb.Append ("{");
408                                 for (int i = 0; i < Arity; ++i) {
409                                         if (i > 0)
410                                                 sb.Append (",");
411
412                                         sb.Append (TypeArguments[i].GetExplicitNameSignatureForDocumentation ());
413                                 }
414                                 sb.Append ("}");
415                         }
416
417                         return sb.ToString ();
418                 }
419
420                 public override string GetSignatureForError ()
421                 {
422                         string s;
423
424                         if (IsNested) {
425                                 s = DeclaringType.GetSignatureForError ();
426                         } else if (MemberDefinition is AnonymousTypeClass) {
427                                 return ((AnonymousTypeClass) MemberDefinition).GetSignatureForError ();
428                         } else {
429                                 s = MemberDefinition.Namespace;
430                         }
431
432                         if (!string.IsNullOrEmpty (s))
433                                 s += ".";
434
435                         return s + Name + GetTypeNameSignature ();
436                 }
437
438                 public string GetSignatureForErrorIncludingAssemblyName ()
439                 {
440                         return string.Format ("{0} [{1}]", GetSignatureForError (), MemberDefinition.DeclaringAssembly.FullName);
441                 }
442
443                 protected virtual string GetTypeNameSignature ()
444                 {
445                         if (!IsGeneric)
446                                 return null;
447
448                         return "<" + TypeManager.CSharpName (MemberDefinition.TypeParameters) + ">";
449                 }
450
451                 public bool ImplementsInterface (TypeSpec iface, bool variantly)
452                 {
453                         var t = this;
454                         do {
455                                 if (t.Interfaces != null) {
456                                         foreach (TypeSpec i in t.Interfaces) {
457                                                 if (i == iface || TypeSpecComparer.IsEqual (i, iface))
458                                                         return true;
459
460                                                 if (variantly && TypeSpecComparer.Variant.IsEqual (i, iface))
461                                                         return true;
462                                         }
463                                 }
464
465                                 // TODO: Why is it needed when we do it during import
466                                 t = t.BaseType;
467                         } while (t != null);
468
469                         return false;
470                 }
471
472                 protected virtual void InitializeMemberCache (bool onlyTypes)
473                 {
474                         try {
475                                 MemberDefinition.LoadMembers (this, onlyTypes, ref cache);
476                         } catch (Exception e) {
477                                 throw new InternalErrorException (e, "Unexpected error when loading type `{0}'", GetSignatureForError ());
478                         }
479
480                         if (onlyTypes)
481                                 state |= StateFlags.PendingMemberCacheMembers;
482                         else
483                                 state &= ~StateFlags.PendingMemberCacheMembers;
484                 }
485
486                 //
487                 // Is @baseClass base implementation of @type. With enabled @dynamicIsEqual the slower
488                 // comparison is used to hide differences between `object' and `dynamic' for generic
489                 // types. Should not be used for comparisons where G<object> != G<dynamic>
490                 //
491                 public static bool IsBaseClass (TypeSpec type, TypeSpec baseClass, bool dynamicIsObject)
492                 {
493                         if (dynamicIsObject && baseClass.IsGeneric) {
494                                 //
495                                 // Returns true for a hierarchies like this when passing baseClass of A<dynamic>
496                                 //
497                                 // class B : A<object> {}
498                                 //
499                                 type = type.BaseType;
500                                 while (type != null) {
501                                         if (TypeSpecComparer.IsEqual (type, baseClass))
502                                                 return true;
503
504                                         type = type.BaseType;
505                                 }
506
507                                 return false;
508                         }
509
510                         while (type != null) {
511                                 type = type.BaseType;
512                                 if (type == baseClass)
513                                         return true;
514                         }
515
516                         return false;
517                 }
518
519                 public static bool IsReferenceType (TypeSpec t)
520                 {
521                         switch (t.Kind) {
522                         case MemberKind.TypeParameter:
523                                 return ((TypeParameterSpec) t).IsReferenceType;
524                         case MemberKind.Struct:
525                         case MemberKind.Enum:
526                                 return false;
527                         case MemberKind.InternalCompilerType:
528                                 //
529                                 // Null is considered to be a reference type
530                                 //                      
531                                 return t == InternalType.NullLiteral || t.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
532                         default:
533                                 return true;
534                         }
535                 }
536
537                 public static bool IsValueType (TypeSpec t)
538                 {
539                         switch (t.Kind) {
540                         case MemberKind.TypeParameter:
541                                 return ((TypeParameterSpec) t).IsValueType;
542                         case MemberKind.Struct:
543                         case MemberKind.Enum:
544                                 return true;
545                         default:
546                                 return false;
547                         }
548                 }
549
550                 public override MemberSpec InflateMember (TypeParameterInflator inflator)
551                 {
552                         var targs = IsGeneric ? MemberDefinition.TypeParameters : TypeSpec.EmptyTypes;
553
554                         //
555                         // When inflating nested type from inside the type instance will be same
556                         // because type parameters are same for all nested types
557                         //
558                         if (DeclaringType == inflator.TypeInstance) {
559                                 return MakeGenericType (inflator.Context, targs);
560                         }
561
562                         return new InflatedTypeSpec (inflator.Context, this, inflator.TypeInstance, targs);
563                 }
564
565                 public InflatedTypeSpec MakeGenericType (IModuleContext context, TypeSpec[] targs)
566                 {
567                         if (targs.Length == 0 && !IsNested)
568                                 throw new ArgumentException ("Empty type arguments for type " + GetSignatureForError ());
569
570                         InflatedTypeSpec instance;
571
572                         if (inflated_instances == null) {
573                                 inflated_instances = new Dictionary<TypeSpec[], InflatedTypeSpec> (TypeSpecComparer.Default);
574
575                                 if (IsNested) {
576                                         instance = this as InflatedTypeSpec;
577                                         if (instance != null) {
578                                                 //
579                                                 // Nested types could be inflated on already inflated instances
580                                                 // Caching this type ensured we are using same instance for
581                                                 // inside/outside inflation using local type parameters
582                                                 //
583                                                 inflated_instances.Add (TypeArguments, instance);
584                                         }
585                                 }
586                         }
587
588                         if (!inflated_instances.TryGetValue (targs, out instance)) {
589                                 if (GetDefinition () != this && !IsNested)
590                                         throw new InternalErrorException ("`{0}' must be type definition or nested non-inflated type to MakeGenericType",
591                                                 GetSignatureForError ());
592
593                                 instance = new InflatedTypeSpec (context, this, declaringType, targs);
594                                 inflated_instances.Add (targs, instance);
595                         }
596
597                         return instance;
598                 }
599
600                 public virtual TypeSpec Mutate (TypeParameterMutator mutator)
601                 {
602                         return this;
603                 }
604
605                 public override List<TypeSpec> ResolveMissingDependencies ()
606                 {
607                         List<TypeSpec> missing = null;
608
609                         if (Kind == MemberKind.MissingType) {
610                                 missing = new List<TypeSpec> ();
611                                 missing.Add (this);
612                                 return missing;
613                         }
614
615                         foreach (var targ in TypeArguments) {
616                                 if (targ.Kind == MemberKind.MissingType) {
617                                         if (missing == null)
618                                                 missing = new List<TypeSpec> ();
619
620                                         missing.Add (targ);
621                                 }
622                         }
623
624                         if (Interfaces != null) {
625                                 foreach (var iface in Interfaces) {
626                                         if (iface.Kind == MemberKind.MissingType) {
627                                                 if (missing == null)
628                                                         missing = new List<TypeSpec> ();
629
630                                                 missing.Add (iface);
631                                         }
632                                 }
633                         }
634
635                         if (missing != null || BaseType == null)
636                                 return missing;
637
638                         return BaseType.ResolveMissingDependencies ();
639                 }
640
641                 public void SetMetaInfo (MetaType info)
642                 {
643                         if (this.info != null)
644                                 throw new InternalErrorException ("MetaInfo reset");
645
646                         this.info = info;
647                 }
648
649                 public void SetExtensionMethodContainer ()
650                 {
651                         modifiers |= Modifiers.METHOD_EXTENSION;
652                 }
653         }
654
655         public sealed class BuiltinTypeSpec : TypeSpec
656         {
657                 public enum Type
658                 {
659                         None = 0,
660
661                         // Ordered carefully for fast compares
662                         FirstPrimitive = 1,
663                         Bool = 1,
664                         Byte = 2,
665                         SByte = 3,
666                         Char = 4,
667                         Short = 5,
668                         UShort = 6,
669                         Int = 7,
670                         UInt = 8,
671                         Long = 9,
672                         ULong = 10,
673                         Float = 11,
674                         Double = 12,
675                         LastPrimitive = 12,
676                         Decimal = 13,
677
678                         IntPtr = 14,
679                         UIntPtr = 15,
680
681                         Object = 16,
682                         Dynamic = 17,
683                         String = 18,
684                         Type = 19,
685
686                         ValueType = 20,
687                         Enum = 21,
688                         Delegate = 22,
689                         MulticastDelegate = 23,
690                         Array = 24,
691
692                         IEnumerator,
693                         IEnumerable,
694                         IDisposable,
695                         Exception,
696                         Attribute,
697                         Other,
698                 }
699
700                 readonly Type type;
701                 readonly string ns;
702                 readonly string name;
703
704                 public BuiltinTypeSpec (MemberKind kind, string ns, string name, Type builtinKind)
705                         : base (kind, null, null, null, Modifiers.PUBLIC)
706                 {
707                         this.type = builtinKind;
708                         this.ns = ns;
709                         this.name = name;
710                 }
711
712                 public BuiltinTypeSpec (string name, Type builtinKind)
713                         : this (MemberKind.InternalCompilerType, "", name, builtinKind)
714                 {
715                         // Make all internal types CLS-compliant, non-obsolete, compact
716                         state = (state & ~(StateFlags.CLSCompliant_Undetected | StateFlags.Obsolete_Undetected | StateFlags.MissingDependency_Undetected)) | StateFlags.CLSCompliant;
717                 }
718
719                 #region Properties
720
721                 public override int Arity {
722                         get {
723                                 return 0;
724                         }
725                 }
726
727                 public override BuiltinTypeSpec.Type BuiltinType {
728                         get {
729                                 return type;
730                         }
731                 }
732
733                 public string FullName {
734                         get {
735                                 return ns + '.' + name;
736                         }
737                 }
738
739                 public override string Name {
740                         get {
741                                 return name;
742                         }
743                 }
744
745                 public string Namespace {
746                         get {
747                                 return ns;
748                         }
749                 }
750
751                 #endregion
752
753                 public static bool IsPrimitiveType (TypeSpec type)
754                 {
755                         return type.BuiltinType >= Type.FirstPrimitive && type.BuiltinType <= Type.LastPrimitive;
756                 }
757
758                 public static bool IsPrimitiveTypeOrDecimal (TypeSpec type)
759                 {
760                         return type.BuiltinType >= Type.FirstPrimitive && type.BuiltinType <= Type.Decimal;
761                 }
762
763                 public override string GetSignatureForError ()
764                 {
765                         switch (Name) {
766                         case "Int32": return "int";
767                         case "Int64": return "long";
768                         case "String": return "string";
769                         case "Boolean": return "bool";
770                         case "Void": return "void";
771                         case "Object": return "object";
772                         case "UInt32": return "uint";
773                         case "Int16": return "short";
774                         case "UInt16": return "ushort";
775                         case "UInt64": return "ulong";
776                         case "Single": return "float";
777                         case "Double": return "double";
778                         case "Decimal": return "decimal";
779                         case "Char": return "char";
780                         case "Byte": return "byte";
781                         case "SByte": return "sbyte";
782                         }
783
784                         if (ns.Length == 0)
785                                 return name;
786
787                         return FullName;
788                 }
789
790                 //
791                 // Returns the size of type if known, otherwise, 0
792                 //
793                 public static int GetSize (TypeSpec type)
794                 {
795                         switch (type.BuiltinType) {
796                         case Type.Int:
797                         case Type.UInt:
798                         case Type.Float:
799                                 return 4;
800                         case Type.Long:
801                         case Type.ULong:
802                         case Type.Double:
803                                 return 8;
804                         case Type.Byte:
805                         case Type.SByte:
806                         case Type.Bool:
807                                 return 1;
808                         case Type.Short:
809                         case Type.Char:
810                         case Type.UShort:
811                                 return 2;
812                         case Type.Decimal:
813                                 return 16;
814                         default:
815                                 return 0;
816                         }
817                 }
818
819                 public void SetDefinition (ITypeDefinition td, MetaType type, Modifiers mod)
820                 {
821                         this.definition = td;
822                         this.info = type;
823                         this.modifiers |= (mod & ~Modifiers.AccessibilityMask);
824                 }
825
826                 public void SetDefinition (TypeSpec ts)
827                 {
828                         this.definition = ts.MemberDefinition;
829                         this.info = ts.GetMetaInfo ();
830                         this.BaseType = ts.BaseType;
831                         this.Interfaces = ts.Interfaces;
832                         this.modifiers = ts.Modifiers;
833                 }
834         }
835
836         static class TypeSpecComparer
837         {
838                 //
839                 // Does strict reference comparion only
840                 //
841                 public static readonly DefaultImpl Default = new DefaultImpl ();
842
843                 public class DefaultImpl : IEqualityComparer<TypeSpec[]>
844                 {
845                         #region IEqualityComparer<TypeSpec[]> Members
846
847                         bool IEqualityComparer<TypeSpec[]>.Equals (TypeSpec[] x, TypeSpec[] y)
848                         {
849                                 if (x == y)
850                                         return true;
851
852                                 if (x.Length != y.Length)
853                                         return false;
854
855                                 for (int i = 0; i < x.Length; ++i)
856                                         if (x[i] != y[i])
857                                                 return false;
858
859                                 return true;
860                         }
861
862                         int IEqualityComparer<TypeSpec[]>.GetHashCode (TypeSpec[] obj)
863                         {
864                                 int hash = 0;
865                                 for (int i = 0; i < obj.Length; ++i)
866                                         hash = (hash << 5) - hash + obj[i].GetHashCode ();
867
868                                 return hash;
869                         }
870
871                         #endregion
872                 }
873
874                 //
875                 // When comparing type signature of overrides or overloads
876                 // this version tolerates different MVARs at same position
877                 //
878                 public static class Override
879                 {
880                         public static bool IsEqual (TypeSpec a, TypeSpec b)
881                         {
882                                 if (a == b)
883                                         return true;
884
885                                 //
886                                 // Consider the following example:
887                                 //
888                                 //     public abstract class A
889                                 //     {
890                                 //        public abstract T Foo<T>();
891                                 //     }
892                                 //
893                                 //     public class B : A
894                                 //     {
895                                 //        public override U Foo<T>() { return default (U); }
896                                 //     }
897                                 //
898                                 // Here, `T' and `U' are method type parameters from different methods
899                                 // (A.Foo and B.Foo), so both `==' and Equals() will fail.
900                                 //
901                                 // However, since we're determining whether B.Foo() overrides A.Foo(),
902                                 // we need to do a signature based comparision and consider them equal.
903                                 //
904
905                                 var tp_a = a as TypeParameterSpec;
906                                 if (tp_a != null) {
907                                         var tp_b = b as TypeParameterSpec;
908                                         return tp_b != null && tp_a.IsMethodOwned == tp_b.IsMethodOwned && tp_a.DeclaredPosition == tp_b.DeclaredPosition;
909                                 }
910
911                                 var ac_a = a as ArrayContainer;
912                                 if (ac_a != null) {
913                                         var ac_b = b as ArrayContainer;
914                                         return ac_b != null && ac_a.Rank == ac_b.Rank && IsEqual (ac_a.Element, ac_b.Element);
915                                 }
916
917                                 if (a.BuiltinType == BuiltinTypeSpec.Type.Dynamic || b.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
918                                         return b.BuiltinType == BuiltinTypeSpec.Type.Object || a.BuiltinType == BuiltinTypeSpec.Type.Object;
919
920                                 if (a.MemberDefinition != b.MemberDefinition)
921                                         return false;
922
923                                 do {
924                                         for (int i = 0; i < a.TypeArguments.Length; ++i) {
925                                                 if (!IsEqual (a.TypeArguments[i], b.TypeArguments[i]))
926                                                         return false;
927                                         }
928
929                                         a = a.DeclaringType;
930                                         b = b.DeclaringType;
931                                 } while (a != null);
932
933                                 return true;
934                         }
935
936                         //
937                         // Compares unordered arrays
938                         //
939                         public static bool IsSame (TypeSpec[] a, TypeSpec[] b)
940                         {
941                                 if (a == b)
942                                         return true;
943
944                                 if (a == null || b == null || a.Length != b.Length)
945                                         return false;
946
947                                 for (int ai = 0; ai < a.Length; ++ai) {
948                                         bool found = false;
949                                         for (int bi = 0; bi < b.Length; ++bi) {
950                                                 if (IsEqual (a[ai], b[bi])) {
951                                                         found = true;
952                                                         break;
953                                                 }
954                                         }
955
956                                         if (!found)
957                                                 return false;
958                                 }
959
960                                 return true;
961                         }
962
963                         public static bool IsEqual (AParametersCollection a, AParametersCollection b)
964                         {
965                                 if (a == b)
966                                         return true;
967
968                                 if (a.Count != b.Count)
969                                         return false;
970
971                                 for (int i = 0; i < a.Count; ++i) {
972                                         if (!IsEqual (a.Types[i], b.Types[i]))
973                                                 return false;
974
975                                         const Parameter.Modifier ref_out = Parameter.Modifier.REF | Parameter.Modifier.OUT;
976                                         if ((a.FixedParameters[i].ModFlags & ref_out) != (b.FixedParameters[i].ModFlags & ref_out))
977                                                 return false;
978                                 }
979
980                                 return true;
981                         }
982                 }
983
984                 //
985                 // Type variance equality comparison
986                 //
987                 public static class Variant
988                 {
989                         public static bool IsEqual (TypeSpec type1, TypeSpec type2)
990                         {
991                                 if (!type1.IsGeneric || !type2.IsGeneric)
992                                         return false;
993
994                                 var target_type_def = type2.MemberDefinition;
995                                 if (type1.MemberDefinition != target_type_def)
996                                         return false;
997
998                                 var t1_targs = type1.TypeArguments;
999                                 var t2_targs = type2.TypeArguments;
1000                                 var targs_definition = target_type_def.TypeParameters;
1001
1002                                 if (!type1.IsInterface && !type1.IsDelegate) {
1003                                         return false;
1004                                 }
1005
1006                                 for (int i = 0; i < targs_definition.Length; ++i) {
1007                                         Variance v = targs_definition[i].Variance;
1008                                         if (v == Variance.None) {
1009                                                 if (t1_targs[i] == t2_targs[i])
1010                                                         continue;
1011                                                 return false;
1012                                         }
1013
1014                                         if (v == Variance.Covariant) {
1015                                                 if (!Convert.ImplicitReferenceConversionExists (t1_targs[i], t2_targs[i]))
1016                                                         return false;
1017                                         } else if (!Convert.ImplicitReferenceConversionExists (t2_targs[i], t1_targs[i])) {
1018                                                 return false;
1019                                         }
1020                                 }
1021
1022                                 return true;
1023                         }
1024                 }
1025
1026                 //
1027                 // Checks whether two generic instances may become equal for some
1028                 // particular instantiation (26.3.1).
1029                 //
1030                 public static class Unify
1031                 {
1032                         //
1033                         // Either @a or @b must be generic type
1034                         //
1035                         public static bool IsEqual (TypeSpec a, TypeSpec b)
1036                         {
1037                                 if (a.MemberDefinition != b.MemberDefinition) {
1038                                         var base_ifaces = a.Interfaces;
1039                                         if (base_ifaces != null) {
1040                                                 foreach (var base_iface in base_ifaces) {
1041                                                         if (base_iface.Arity > 0 && IsEqual (base_iface, b))
1042                                                                 return true;
1043                                                 }
1044                                         }
1045
1046                                         return false;
1047                                 }
1048
1049                                 var ta = a.TypeArguments;
1050                                 var tb = b.TypeArguments;
1051                                 for (int i = 0; i < ta.Length; i++) {
1052                                         if (!MayBecomeEqualGenericTypes (ta[i], tb[i]))
1053                                                 return false;
1054                                 }
1055
1056                                 return true;
1057                         }
1058
1059                         static bool ContainsTypeParameter (TypeSpec tparam, TypeSpec type)
1060                         {
1061                                 TypeSpec[] targs = type.TypeArguments;
1062                                 for (int i = 0; i < targs.Length; i++) {
1063                                         if (tparam == targs[i])
1064                                                 return true;
1065
1066                                         if (ContainsTypeParameter (tparam, targs[i]))
1067                                                 return true;
1068                                 }
1069
1070                                 return false;
1071                         }
1072
1073                         /// <summary>
1074                         ///   Check whether `a' and `b' may become equal generic types.
1075                         ///   The algorithm to do that is a little bit complicated.
1076                         /// </summary>
1077                         static bool MayBecomeEqualGenericTypes (TypeSpec a, TypeSpec b)
1078                         {
1079                                 if (a.IsGenericParameter) {
1080                                         //
1081                                         // If a is an array of a's type, they may never
1082                                         // become equal.
1083                                         //
1084                                         if (b.IsArray)
1085                                                 return false;
1086
1087                                         //
1088                                         // If b is a generic parameter or an actual type,
1089                                         // they may become equal:
1090                                         //
1091                                         //    class X<T,U> : I<T>, I<U>
1092                                         //    class X<T> : I<T>, I<float>
1093                                         // 
1094                                         if (b.IsGenericParameter)
1095                                                 return a != b && a.DeclaringType == b.DeclaringType;
1096
1097                                         //
1098                                         // We're now comparing a type parameter with a
1099                                         // generic instance.  They may become equal unless
1100                                         // the type parameter appears anywhere in the
1101                                         // generic instance:
1102                                         //
1103                                         //    class X<T,U> : I<T>, I<X<U>>
1104                                         //        -> error because you could instanciate it as
1105                                         //           X<X<int>,int>
1106                                         //
1107                                         //    class X<T> : I<T>, I<X<T>> -> ok
1108                                         //
1109
1110                                         return !ContainsTypeParameter (a, b);
1111                                 }
1112
1113                                 if (b.IsGenericParameter)
1114                                         return MayBecomeEqualGenericTypes (b, a);
1115
1116                                 //
1117                                 // At this point, neither a nor b are a type parameter.
1118                                 //
1119                                 // If one of them is a generic instance, compare them (if the
1120                                 // other one is not a generic instance, they can never
1121                                 // become equal).
1122                                 //
1123                                 if (TypeManager.IsGenericType (a) || TypeManager.IsGenericType (b))
1124                                         return IsEqual (a, b);
1125
1126                                 //
1127                                 // If both of them are arrays.
1128                                 //
1129                                 var a_ac = a as ArrayContainer;
1130                                 if (a_ac != null) {
1131                                         var b_ac = b as ArrayContainer;
1132                                         if (b_ac == null || a_ac.Rank != b_ac.Rank)
1133                                                 return false;
1134
1135                                         return MayBecomeEqualGenericTypes (a_ac.Element, b_ac.Element);
1136                                 }
1137
1138                                 //
1139                                 // Ok, two ordinary types.
1140                                 //
1141                                 return false;
1142                         }
1143                 }
1144
1145                 public static bool Equals (TypeSpec[] x, TypeSpec[] y)
1146                 {
1147                         if (x == y)
1148                                 return true;
1149
1150                         if (x.Length != y.Length)
1151                                 return false;
1152
1153                         for (int i = 0; i < x.Length; ++i)
1154                                 if (!IsEqual (x[i], y[i]))
1155                                         return false;
1156
1157                         return true;
1158                 }
1159
1160                 //
1161                 // Identity type conversion
1162                 //
1163                 // Default reference comparison, it has to be used when comparing
1164                 // two possible dynamic/internal types
1165                 //
1166                 public static bool IsEqual (TypeSpec a, TypeSpec b)
1167                 {
1168                         if (a == b) {
1169                                 // This also rejects dynamic == dynamic
1170                                 return a.Kind != MemberKind.InternalCompilerType || a.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
1171                         }
1172
1173                         if (a == null || b == null)
1174                                 return false;
1175
1176                         if (a.IsArray) {
1177                                 var a_a = (ArrayContainer) a;
1178                                 var b_a = b as ArrayContainer;
1179                                 if (b_a == null)
1180                                         return false;
1181
1182                                 return a_a.Rank == b_a.Rank && IsEqual (a_a.Element, b_a.Element);
1183                         }
1184
1185                         if (!a.IsGeneric || !b.IsGeneric) {
1186                                 //
1187                                 // object and dynamic are considered equivalent there is an identity conversion
1188                                 // between object and dynamic, and between constructed types that are the same
1189                                 // when replacing all occurences of dynamic with object.
1190                                 //
1191                                 if (a.BuiltinType == BuiltinTypeSpec.Type.Dynamic || b.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1192                                         return b.BuiltinType == BuiltinTypeSpec.Type.Object || a.BuiltinType == BuiltinTypeSpec.Type.Object;
1193
1194                                 return false;
1195                         }
1196
1197                         if (a.MemberDefinition != b.MemberDefinition)
1198                                 return false;
1199
1200                         do {
1201                                 if (!Equals (a.TypeArguments, b.TypeArguments))
1202                                         return false;
1203
1204                                 a = a.DeclaringType;
1205                                 b = b.DeclaringType;
1206                         } while (a != null);
1207
1208                         return true;
1209                 }
1210         }
1211
1212         public interface ITypeDefinition : IMemberDefinition
1213         {
1214                 IAssemblyDefinition DeclaringAssembly { get; }
1215                 string Namespace { get; }
1216                 int TypeParametersCount { get; }
1217                 TypeParameterSpec[] TypeParameters { get; }
1218
1219                 TypeSpec GetAttributeCoClass ();
1220                 string GetAttributeDefaultMember ();
1221                 AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa);
1222                 bool IsInternalAsPublic (IAssemblyDefinition assembly);
1223                 void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache);
1224         }
1225
1226         class InternalType : TypeSpec, ITypeDefinition
1227         {
1228                 public static readonly InternalType AnonymousMethod = new InternalType ("anonymous method");
1229                 public static readonly InternalType Arglist = new InternalType ("__arglist");
1230                 public static readonly InternalType MethodGroup = new InternalType ("method group");
1231                 public static readonly InternalType NullLiteral = new InternalType ("null");
1232                 public static readonly InternalType FakeInternalType = new InternalType ("<fake$type>");
1233                 public static readonly InternalType Namespace = new InternalType ("<namespace>");
1234
1235                 readonly string name;
1236
1237                 InternalType (string name, MemberCache cache)
1238                         : this (name)
1239                 {
1240                         this.cache = cache;
1241                 }
1242
1243                 InternalType (string name)
1244                         : base (MemberKind.InternalCompilerType, null, null, null, Modifiers.PUBLIC)
1245                 {
1246                         this.name = name;
1247                         this.definition = this;
1248                         cache = MemberCache.Empty;
1249
1250                         // Make all internal types CLS-compliant, non-obsolete
1251                         state = (state & ~(StateFlags.CLSCompliant_Undetected | StateFlags.Obsolete_Undetected)) | StateFlags.CLSCompliant;
1252                 }
1253
1254                 #region Properties
1255
1256                 public override int Arity {
1257                         get {
1258                                 return 0;
1259                         }
1260                 }
1261
1262                 IAssemblyDefinition ITypeDefinition.DeclaringAssembly {
1263                         get {
1264                                 throw new NotImplementedException ();
1265                         }
1266                 }
1267
1268                 bool IMemberDefinition.IsImported {
1269                         get {
1270                                 return false;
1271                         }
1272                 }
1273
1274                 public override string Name {
1275                         get {
1276                                 return name;
1277                         }
1278                 }
1279
1280                 string ITypeDefinition.Namespace {
1281                         get {
1282                                 return null;
1283                         }
1284                 }
1285
1286                 int ITypeDefinition.TypeParametersCount {
1287                         get {
1288                                 return 0;
1289                         }
1290                 }
1291
1292                 TypeParameterSpec[] ITypeDefinition.TypeParameters {
1293                         get {
1294                                 return null;
1295                         }
1296                 }
1297
1298                 #endregion
1299
1300                 public override string GetSignatureForError ()
1301                 {
1302                         return name;
1303                 }
1304
1305                 #region ITypeDefinition Members
1306
1307                 TypeSpec ITypeDefinition.GetAttributeCoClass ()
1308                 {
1309                         return null;
1310                 }
1311
1312                 string ITypeDefinition.GetAttributeDefaultMember ()
1313                 {
1314                         return null;
1315                 }
1316
1317                 AttributeUsageAttribute ITypeDefinition.GetAttributeUsage (PredefinedAttribute pa)
1318                 {
1319                         return null;
1320                 }
1321
1322                 bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly)
1323                 {
1324                         throw new NotImplementedException ();
1325                 }
1326
1327                 void ITypeDefinition.LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
1328                 {
1329                         throw new NotImplementedException ();
1330                 }
1331
1332                 string[] IMemberDefinition.ConditionalConditions ()
1333                 {
1334                         return null;
1335                 }
1336
1337                 ObsoleteAttribute IMemberDefinition.GetAttributeObsolete ()
1338                 {
1339                         return null;
1340                 }
1341
1342                 bool? IMemberDefinition.CLSAttributeValue {
1343                         get {
1344                                 return null;
1345                         }
1346                 }
1347
1348                 void IMemberDefinition.SetIsAssigned ()
1349                 {
1350                 }
1351
1352                 void IMemberDefinition.SetIsUsed ()
1353                 {
1354                 }
1355
1356                 #endregion
1357         }
1358
1359         public abstract class ElementTypeSpec : TypeSpec, ITypeDefinition
1360         {
1361                 protected ElementTypeSpec (MemberKind kind, TypeSpec element, MetaType info)
1362                         : base (kind, element.DeclaringType, null, info, element.Modifiers)
1363                 {
1364                         this.Element = element;
1365
1366                         // Some flags can be copied directly from the element
1367                         const StateFlags shared_flags = StateFlags.CLSCompliant | StateFlags.CLSCompliant_Undetected
1368                                 | StateFlags.Obsolete | StateFlags.Obsolete_Undetected | StateFlags.HasDynamicElement;
1369                         state &= ~shared_flags;
1370                         state |= (element.state & shared_flags);
1371
1372                         if (element.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1373                                 state |= StateFlags.HasDynamicElement;
1374
1375                         // Has to use its own type definition instead of just element definition to
1376                         // correctly identify itself for cases like x.MemberDefininition == predefined.MemberDefinition
1377                         this.definition = this;
1378
1379                         cache = MemberCache.Empty;
1380                 }
1381
1382                 #region Properties
1383
1384                 public TypeSpec Element { get; private set; }
1385
1386                 public override string Name {
1387                         get {
1388                                 throw new NotSupportedException ();
1389                         }
1390                 }
1391
1392                 #endregion
1393
1394                 public override ObsoleteAttribute GetAttributeObsolete ()
1395                 {
1396                         return Element.GetAttributeObsolete ();
1397                 }
1398
1399                 protected virtual string GetPostfixSignature ()
1400                 {
1401                         return null;
1402                 }
1403
1404                 public override string GetSignatureForDocumentation ()
1405                 {
1406                         return Element.GetSignatureForDocumentation () + GetPostfixSignature ();
1407                 }
1408
1409                 public override string GetSignatureForError ()
1410                 {
1411                         return Element.GetSignatureForError () + GetPostfixSignature ();
1412                 }
1413
1414                 public override TypeSpec Mutate (TypeParameterMutator mutator)
1415                 {
1416                         var me = Element.Mutate (mutator);
1417                         if (me == Element)
1418                                 return this;
1419
1420                         var mutated = (ElementTypeSpec) MemberwiseClone ();
1421                         mutated.Element = me;
1422                         mutated.info = null;
1423                         return mutated;
1424                 }
1425
1426                 #region ITypeDefinition Members
1427
1428                 IAssemblyDefinition ITypeDefinition.DeclaringAssembly {
1429                         get {
1430                                 return Element.MemberDefinition.DeclaringAssembly;
1431                         }
1432                 }
1433
1434                 bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly)
1435                 {
1436                         return Element.MemberDefinition.IsInternalAsPublic (assembly);
1437                 }
1438
1439                 public string Namespace {
1440                         get { throw new NotImplementedException (); }
1441                 }
1442
1443                 public int TypeParametersCount {
1444                         get {
1445                                 return 0;
1446                         }
1447                 }
1448
1449                 public TypeParameterSpec[] TypeParameters {
1450                         get {
1451                                 throw new NotSupportedException ();
1452                         }
1453                 }
1454
1455                 public TypeSpec GetAttributeCoClass ()
1456                 {
1457                         return Element.MemberDefinition.GetAttributeCoClass ();
1458                 }
1459
1460                 public string GetAttributeDefaultMember ()
1461                 {
1462                         return Element.MemberDefinition.GetAttributeDefaultMember ();
1463                 }
1464
1465                 public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
1466                 {
1467                         Element.MemberDefinition.LoadMembers (declaringType, onlyTypes, ref cache);
1468                 }
1469
1470                 public bool IsImported {
1471                         get {
1472                                 return Element.MemberDefinition.IsImported;
1473                         }
1474                 }
1475
1476                 public string[] ConditionalConditions ()
1477                 {
1478                         return Element.MemberDefinition.ConditionalConditions ();
1479                 }
1480
1481                 bool? IMemberDefinition.CLSAttributeValue {
1482                         get {
1483                                 return Element.MemberDefinition.CLSAttributeValue;
1484                         }
1485                 }
1486
1487                 public void SetIsAssigned ()
1488                 {
1489                         Element.MemberDefinition.SetIsAssigned ();
1490                 }
1491
1492                 public void SetIsUsed ()
1493                 {
1494                         Element.MemberDefinition.SetIsUsed ();
1495                 }
1496
1497                 #endregion
1498         }
1499
1500         public class ArrayContainer : ElementTypeSpec
1501         {
1502                 public struct TypeRankPair : IEquatable<TypeRankPair>
1503                 {
1504                         TypeSpec ts;
1505                         int rank;
1506
1507                         public TypeRankPair (TypeSpec ts, int rank)
1508                         {
1509                                 this.ts = ts;
1510                                 this.rank = rank;
1511                         }
1512
1513                         public override int GetHashCode ()
1514                         {
1515                                 return ts.GetHashCode () ^ rank.GetHashCode ();
1516                         }
1517
1518                         #region IEquatable<Tuple<T1,T2>> Members
1519
1520                         public bool Equals (TypeRankPair other)
1521                         {
1522                                 return other.ts == ts && other.rank == rank;
1523                         }
1524
1525                         #endregion
1526                 }
1527
1528                 readonly int rank;
1529                 readonly ModuleContainer module;
1530
1531                 private ArrayContainer (ModuleContainer module, TypeSpec element, int rank)
1532                         : base (MemberKind.ArrayType, element, null)
1533                 {
1534                         this.module = module;
1535                         this.rank = rank;
1536                 }
1537
1538                 public int Rank {
1539                         get {
1540                                 return rank;
1541                         }
1542                 }
1543
1544                 public MethodInfo GetConstructor ()
1545                 {
1546                         var mb = module.Builder;
1547
1548                         var arg_types = new MetaType[rank];
1549                         for (int i = 0; i < rank; i++)
1550                                 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1551
1552                         var ctor = mb.GetArrayMethod (
1553                                 GetMetaInfo (), Constructor.ConstructorName,
1554                                 CallingConventions.HasThis,
1555                                 null, arg_types);
1556
1557                         return ctor;
1558                 }
1559
1560                 public MethodInfo GetAddressMethod ()
1561                 {
1562                         var mb = module.Builder;
1563
1564                         var arg_types = new MetaType[rank];
1565                         for (int i = 0; i < rank; i++)
1566                                 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1567
1568                         var address = mb.GetArrayMethod (
1569                                 GetMetaInfo (), "Address",
1570                                 CallingConventions.HasThis | CallingConventions.Standard,
1571                                 ReferenceContainer.MakeType (module, Element).GetMetaInfo (), arg_types);
1572
1573                         return address;
1574                 }
1575
1576                 public MethodInfo GetGetMethod ()
1577                 {
1578                         var mb = module.Builder;
1579
1580                         var arg_types = new MetaType[rank];
1581                         for (int i = 0; i < rank; i++)
1582                                 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1583
1584                         var get = mb.GetArrayMethod (
1585                                 GetMetaInfo (), "Get",
1586                                 CallingConventions.HasThis | CallingConventions.Standard,
1587                                 Element.GetMetaInfo (), arg_types);
1588
1589                         return get;
1590                 }
1591
1592                 public MethodInfo GetSetMethod ()
1593                 {
1594                         var mb = module.Builder;
1595
1596                         var arg_types = new MetaType[rank + 1];
1597                         for (int i = 0; i < rank; i++)
1598                                 arg_types[i] = module.Compiler.BuiltinTypes.Int.GetMetaInfo ();
1599
1600                         arg_types[rank] = Element.GetMetaInfo ();
1601
1602                         var set = mb.GetArrayMethod (
1603                                 GetMetaInfo (), "Set",
1604                                 CallingConventions.HasThis | CallingConventions.Standard,
1605                                 module.Compiler.BuiltinTypes.Void.GetMetaInfo (), arg_types);
1606
1607                         return set;
1608                 }
1609
1610                 public override MetaType GetMetaInfo ()
1611                 {
1612                         if (info == null) {
1613                                 if (rank == 1)
1614                                         info = Element.GetMetaInfo ().MakeArrayType ();
1615                                 else
1616                                         info = Element.GetMetaInfo ().MakeArrayType (rank);
1617                         }
1618
1619                         return info;
1620                 }
1621
1622                 protected override string GetPostfixSignature()
1623                 {
1624                         return GetPostfixSignature (rank);
1625                 }
1626
1627                 public static string GetPostfixSignature (int rank)
1628                 {
1629                         StringBuilder sb = new StringBuilder ();
1630                         sb.Append ("[");
1631                         for (int i = 1; i < rank; i++) {
1632                                 sb.Append (",");
1633                         }
1634                         sb.Append ("]");
1635
1636                         return sb.ToString ();
1637                 }
1638
1639                 public override string GetSignatureForDocumentation ()
1640                 {
1641                         var e = Element;
1642                         List<int> ranks = new List<int> (2);
1643                         ranks.Add (rank);
1644
1645                         while (e is ArrayContainer) {
1646                                 var ac = (ArrayContainer) e;
1647                                 ranks.Add (ac.rank);
1648                                 e = ac.Element;
1649                         }
1650
1651                         StringBuilder sb = new StringBuilder (e.GetSignatureForDocumentation ());
1652                         for (int r = 0; r < ranks.Count; ++r) {
1653                                 sb.Append ("[");
1654                                 for (int i = 1; i < ranks[r]; i++) {
1655                                         if (i == 1)
1656                                                 sb.Append ("0:");
1657
1658                                         sb.Append (",0:");
1659                                 }
1660                                 sb.Append ("]");
1661                         }
1662
1663                         return sb.ToString ();
1664                 }
1665
1666                 public static ArrayContainer MakeType (ModuleContainer module, TypeSpec element)
1667                 {
1668                         return MakeType (module, element, 1);
1669                 }
1670
1671                 public static ArrayContainer MakeType (ModuleContainer module, TypeSpec element, int rank)
1672                 {
1673                         ArrayContainer ac;
1674                         var key = new TypeRankPair (element, rank);
1675                         if (!module.ArrayTypesCache.TryGetValue (key, out ac)) {
1676                                 ac = new ArrayContainer (module, element, rank) {
1677                                         BaseType = module.Compiler.BuiltinTypes.Array
1678                                 };
1679
1680                                 module.ArrayTypesCache.Add (key, ac);
1681                         }
1682
1683                         return ac;
1684                 }
1685         }
1686
1687         class ReferenceContainer : ElementTypeSpec
1688         {
1689                 private ReferenceContainer (TypeSpec element)
1690                         : base (MemberKind.Class, element, null)        // TODO: Kind.Class is most likely wrong
1691                 {
1692                 }
1693
1694                 public override MetaType GetMetaInfo ()
1695                 {
1696                         if (info == null) {
1697                                 info = Element.GetMetaInfo ().MakeByRefType ();
1698                         }
1699
1700                         return info;
1701                 }
1702
1703                 public static ReferenceContainer MakeType (ModuleContainer module, TypeSpec element)
1704                 {
1705                         ReferenceContainer pc;
1706                         if (!module.ReferenceTypesCache.TryGetValue (element, out pc)) {
1707                                 pc = new ReferenceContainer (element);
1708                                 module.ReferenceTypesCache.Add (element, pc);
1709                         }
1710
1711                         return pc;
1712                 }
1713         }
1714
1715         class PointerContainer : ElementTypeSpec
1716         {
1717                 private PointerContainer (TypeSpec element)
1718                         : base (MemberKind.PointerType, element, null)
1719                 {
1720                         // It's never CLS-Compliant
1721                         state &= ~StateFlags.CLSCompliant_Undetected;
1722                 }
1723
1724                 public override MetaType GetMetaInfo ()
1725                 {
1726                         if (info == null) {
1727                                 info = Element.GetMetaInfo ().MakePointerType ();
1728                         }
1729
1730                         return info;
1731                 }
1732
1733                 protected override string GetPostfixSignature()
1734                 {
1735                         return "*";
1736                 }
1737
1738                 public static PointerContainer MakeType (ModuleContainer module, TypeSpec element)
1739                 {
1740                         PointerContainer pc;
1741                         if (!module.PointerTypesCache.TryGetValue (element, out pc)) {
1742                                 pc = new PointerContainer (element);
1743                                 module.PointerTypesCache.Add (element, pc);
1744                         }
1745
1746                         return pc;
1747                 }
1748         }
1749 }