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