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