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