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