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