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