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