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