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