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