More conversion tweaks for dynamic in using statement
[mono.git] / mcs / mcs / typespec.cs
index f5b8df634cf636fe1c02cda4a648ab2e64f614a8..99b8919ef35cf9b80dce99873fa3e795334da6e1 100644 (file)
@@ -66,6 +66,12 @@ namespace Mono.CSharp
                        }
                }
 
+               public bool HasDynamicElement {
+                       get {
+                               return (state & StateFlags.HasDynamicElement) != 0;
+                       }
+               }
+
                public virtual IList<TypeSpec> Interfaces {
                        get {
                                return ifaces;
@@ -194,9 +200,12 @@ namespace Mono.CSharp
                        }
                }
 
-               public virtual MemberCache MemberCacheTypes {
+               public MemberCache MemberCacheTypes {
                        get {
-                               return MemberCache;
+                               if (cache == null)
+                                       InitializeMemberCache (true);
+
+                               return cache;
                        }
                }       
 
@@ -269,6 +278,8 @@ namespace Mono.CSharp
 
                        if (IsNested) {
                                s = DeclaringType.GetSignatureForError ();
+                       } else if (MemberDefinition is AnonymousTypeClass) {
+                               return ((AnonymousTypeClass) MemberDefinition).GetSignatureForError ();
                        } else {
                                s = MemberDefinition.Namespace;
                        }
@@ -287,13 +298,16 @@ namespace Mono.CSharp
                        return "<" + TypeManager.CSharpName (MemberDefinition.TypeParameters) + ">";
                }
 
-               public bool ImplementsInterface (TypeSpec iface)
+               public bool ImplementsInterface (TypeSpec iface, bool variantly)
                {
                        var t = this;
                        do {
                                if (t.Interfaces != null) {     // TODO: Try t.iface
                                        foreach (TypeSpec i in t.Interfaces) {
-                                               if (i == iface || TypeSpecComparer.Variant.IsEqual (i, iface))
+                                               if (i == iface || TypeSpecComparer.IsEqual (i, iface))
+                                                       return true;
+
+                                               if (variantly && TypeSpecComparer.Variant.IsEqual (i, iface))
                                                        return true;
                                        }
                                }
@@ -306,14 +320,43 @@ namespace Mono.CSharp
 
                protected virtual void InitializeMemberCache (bool onlyTypes)
                {
-                       //
-                       // Not interested in members of nested private types
-                       //
-                       if (IsPrivate) {
-                               cache = new MemberCache (0);
-                       } else {
-                               cache = MemberDefinition.LoadMembers (this);
+                       MemberDefinition.LoadMembers (this, onlyTypes, ref cache);
+
+                       if (onlyTypes)
+                               state |= StateFlags.PendingMemberCacheMembers;
+                       else
+                               state &= ~StateFlags.PendingMemberCacheMembers;
+               }
+
+               //
+               // Is @baseClass base implementation of @type. With enabled @dynamicIsEqual the slower
+               // comparison is used to hide differences between `object' and `dynamic' for generic
+               // types. Should not be used for comparisons where G<object> != G<dynamic>
+               //
+               public static bool IsBaseClass (TypeSpec type, TypeSpec baseClass, bool dynamicIsObject)
+               {
+                       if (dynamicIsObject && baseClass.IsGeneric) {
+                               //
+                               // Returns true for a hierarchies like this when passing baseClass of A<dynamic>
+                               //
+                               // class B : A<object> {}
+                               //
+                               while (type != null) {
+                                       type = type.BaseType;
+                                       if (TypeSpecComparer.IsEqual (type, baseClass))
+                                               return true;
+                               }
+
+                               return false;
+                       }
+
+                       while (type != null) {
+                               type = type.BaseType;
+                               if (type == baseClass)
+                                       return true;
                        }
+
+                       return false;
                }
 
                public override MemberSpec InflateMember (TypeParameterInflator inflator)
@@ -333,7 +376,7 @@ namespace Mono.CSharp
                public InflatedTypeSpec MakeGenericType (TypeSpec[] targs)
                {
                        if (targs.Length == 0 && !IsNested)
-                               throw new ArgumentException ("Empty type arguments");
+                               throw new ArgumentException ("Empty type arguments for type " + GetSignatureForError ());
 
                        InflatedTypeSpec instance;
 
@@ -342,7 +385,8 @@ namespace Mono.CSharp
 
                        if (!inflated_instances.TryGetValue (targs, out instance)) {
                                if (GetDefinition () != this && !IsNested)
-                                       throw new InternalErrorException ("Only type definition or nested non-inflated types can be used to call MakeGenericType");
+                                       throw new InternalErrorException ("`{0}' must be type definition or nested non-inflated type to MakeGenericType",
+                                               GetSignatureForError ());
 
                                instance = new InflatedTypeSpec (this, declaringType, targs);
                                inflated_instances.Add (targs, instance);
@@ -378,6 +422,9 @@ namespace Mono.CSharp
                public PredefinedTypeSpec (MemberKind kind, string ns, string name)
                        : base (kind, null, null, null, Modifiers.PUBLIC)
                {
+                       if (kind == MemberKind.Struct)
+                               modifiers |= Modifiers.SEALED;
+
                        this.name = name;
                        this.ns = ns;
                }
@@ -446,16 +493,15 @@ namespace Mono.CSharp
        static class TypeSpecComparer
        {
                //
-               // Default reference comparison, it has to be used when comparing
-               // two possible dynamic/internal types
+               // Does strict reference comparion only
                //
                public static readonly DefaultImpl Default = new DefaultImpl ();
 
-               public class DefaultImpl : IEqualityComparer<TypeSpec[]>, IEqualityComparer<Tuple<TypeSpec, TypeSpec[]>>
+               public class DefaultImpl : IEqualityComparer<TypeSpec[]>
                {
                        #region IEqualityComparer<TypeSpec[]> Members
 
-                       public bool Equals (TypeSpec[] x, TypeSpec[] y)
+                       bool IEqualityComparer<TypeSpec[]>.Equals (TypeSpec[] x, TypeSpec[] y)
                        {
                                if (x == y)
                                        return true;
@@ -464,13 +510,13 @@ namespace Mono.CSharp
                                        return false;
 
                                for (int i = 0; i < x.Length; ++i)
-                                       if (!IsEqual (x[i], y[i]))
+                                       if (x[i] != y[i])
                                                return false;
 
                                return true;
                        }
 
-                       public int GetHashCode (TypeSpec[] obj)
+                       int IEqualityComparer<TypeSpec[]>.GetHashCode (TypeSpec[] obj)
                        {
                                int hash = 0;
                                for (int i = 0; i < obj.Length; ++i)
@@ -480,45 +526,6 @@ namespace Mono.CSharp
                        }
 
                        #endregion
-
-                       #region IEqualityComparer<Tuple<TypeSpec,TypeSpec[]>> Members
-
-                       bool IEqualityComparer<Tuple<TypeSpec, TypeSpec[]>>.Equals (Tuple<TypeSpec, TypeSpec[]> x, Tuple<TypeSpec, TypeSpec[]> y)
-                       {
-                               return Equals (x.Item2, y.Item2) && x.Item1 == y.Item1;
-                       }
-
-                       int IEqualityComparer<Tuple<TypeSpec, TypeSpec[]>>.GetHashCode (Tuple<TypeSpec, TypeSpec[]> obj)
-                       {
-                               return GetHashCode (obj.Item2) ^ obj.Item1.GetHashCode ();
-                       }
-
-                       #endregion
-
-                       //
-                       // Identity type conversion
-                       //
-                       public bool IsEqual (TypeSpec a, TypeSpec b)
-                       {
-                               if (a == b)
-                                       return a.Kind != MemberKind.InternalCompilerType;
-
-                               //
-                               // object and dynamic are considered equivalent there is an identity conversion
-                               // between object and dynamic, and between constructed types that are the same
-                               // when replacing all occurences of dynamic with object.
-                               //
-                               if (a == InternalType.Dynamic || b == InternalType.Dynamic)
-                                       return b == TypeManager.object_type || a == TypeManager.object_type;
-
-                               if (a == null || !a.IsGeneric || b == null || !b.IsGeneric)
-                                       return false;
-
-                               if (a.MemberDefinition != b.MemberDefinition)
-                                       return false;
-
-                               return Equals (a.TypeArguments, b.TypeArguments);
-                       }
                }
 
                //
@@ -652,7 +659,7 @@ namespace Mono.CSharp
                                var targs_definition = target_type_def.TypeParameters;
 
                                if (!type1.IsInterface && !type1.IsDelegate) {
-                                       return Default.Equals (t1_targs, t2_targs);
+                                       return false;
                                }
 
                                for (int i = 0; i < targs_definition.Length; ++i) {
@@ -784,6 +791,71 @@ namespace Mono.CSharp
                                return false;
                        }
                }
+
+               public static bool Equals (TypeSpec[] x, TypeSpec[] y)
+               {
+                       if (x == y)
+                               return true;
+
+                       if (x.Length != y.Length)
+                               return false;
+
+                       for (int i = 0; i < x.Length; ++i)
+                               if (!IsEqual (x[i], y[i]))
+                                       return false;
+
+                       return true;
+               }
+
+               //
+               // Identity type conversion
+               //
+               // Default reference comparison, it has to be used when comparing
+               // two possible dynamic/internal types
+               //
+               public static bool IsEqual (TypeSpec a, TypeSpec b)
+               {
+                       if (a == b) {
+                               // This also rejects dynamic == dynamic
+                               return a.Kind != MemberKind.InternalCompilerType || a == InternalType.Dynamic;
+                       }
+
+                       //
+                       // object and dynamic are considered equivalent there is an identity conversion
+                       // between object and dynamic, and between constructed types that are the same
+                       // when replacing all occurences of dynamic with object.
+                       //
+                       if (a == InternalType.Dynamic || b == InternalType.Dynamic)
+                               return b == TypeManager.object_type || a == TypeManager.object_type;
+
+                       if (a == null)
+                               return false;
+
+                       if (a.IsArray) {
+                               var a_a = (ArrayContainer) a;
+                               var b_a = b as ArrayContainer;
+                               if (b_a == null)
+                                       return false;
+
+                               return IsEqual (a_a.Element, b_a.Element) && a_a.Rank == b_a.Rank;
+                       }
+
+                       if (!a.IsGeneric || b == null || !b.IsGeneric)
+                               return false;
+
+                       if (a.MemberDefinition != b.MemberDefinition)
+                               return false;
+
+                       do {
+                               if (!Equals (a.TypeArguments, b.TypeArguments))
+                                       return false;
+
+                               a = a.DeclaringType;
+                               b = b.DeclaringType;
+                       } while (a != null);
+
+                       return true;
+               }
        }
 
        public interface ITypeDefinition : IMemberDefinition
@@ -795,30 +867,31 @@ namespace Mono.CSharp
                TypeSpec GetAttributeCoClass ();
                string GetAttributeDefaultMember ();
                AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa);
-               MemberCache LoadMembers (TypeSpec declaringType);
+               void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache);
        }
 
-       class InternalType : TypeSpec
+       class InternalType : TypeSpec, ITypeDefinition
        {
                public static readonly InternalType AnonymousMethod = new InternalType ("anonymous method");
                public static readonly InternalType Arglist = new InternalType ("__arglist");
-               public static readonly InternalType Dynamic = new InternalType ("dynamic", typeof (object));
+               public static readonly InternalType Dynamic = new InternalType ("dynamic", null);
                public static readonly InternalType MethodGroup = new InternalType ("method group");
-               public static readonly InternalType Null = new InternalType ("null", typeof (object));
+               public static readonly InternalType Null = new InternalType ("null");
                public static readonly InternalType FakeInternalType = new InternalType ("<fake$type>");
 
                readonly string name;
 
-               InternalType (string name, Type metaInfo)
+               InternalType (string name, MemberCache cache)
                        : this (name)
                {
-                       info = metaInfo;
+                       this.cache = cache;
                }
 
                InternalType (string name)
                        : base (MemberKind.InternalCompilerType, null, null, null, Modifiers.PUBLIC)
                {
                        this.name = name;
+                       this.definition = this;
                        cache = MemberCache.Empty;
 
                        // Make all internal types CLS-compliant, non-obsolete
@@ -833,18 +906,95 @@ namespace Mono.CSharp
                        }
                }
 
+               System.Reflection.Assembly IMemberDefinition.Assembly {
+                       get {
+                               throw new NotImplementedException ();
+                       }
+               }
+
+               bool IMemberDefinition.IsImported {
+                       get {
+                               return false;
+                       }
+               }
+
                public override string Name {
                        get {
                                return name;
                        }
                }
 
+               string ITypeDefinition.Namespace {
+                       get {
+                               return null;
+                       }
+               }
+
+               int ITypeDefinition.TypeParametersCount {
+                       get {
+                               return 0;
+                       }
+               }
+
+               TypeParameterSpec[] ITypeDefinition.TypeParameters {
+                       get {
+                               return null;
+                       }
+               }
+
                #endregion
 
                public override string GetSignatureForError ()
                {
                        return name;
                }
+
+               #region ITypeDefinition Members
+
+               TypeSpec ITypeDefinition.GetAttributeCoClass ()
+               {
+                       return null;
+               }
+
+               string ITypeDefinition.GetAttributeDefaultMember ()
+               {
+                       return null;
+               }
+
+               AttributeUsageAttribute ITypeDefinition.GetAttributeUsage (PredefinedAttribute pa)
+               {
+                       return null;
+               }
+
+               void ITypeDefinition.LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               string[] IMemberDefinition.ConditionalConditions ()
+               {
+                       return null;
+               }
+
+               ObsoleteAttribute IMemberDefinition.GetAttributeObsolete ()
+               {
+                       return null;
+               }
+
+               bool IMemberDefinition.IsNotCLSCompliant ()
+               {
+                       return false;
+               }
+
+               void IMemberDefinition.SetIsAssigned ()
+               {
+               }
+
+               void IMemberDefinition.SetIsUsed ()
+               {
+               }
+
+               #endregion
        }
 
        public abstract class ElementTypeSpec : TypeSpec, ITypeDefinition
@@ -853,6 +1003,8 @@ namespace Mono.CSharp
                        : base (kind, element.DeclaringType, null, info, element.Modifiers)
                {
                        this.Element = element;
+                       if (element == InternalType.Dynamic || element.HasDynamicElement)
+                               state |= StateFlags.HasDynamicElement;
 
                        // Has to use its own type definition instead of just element definition to
                        // correctly identify itself for cases like x.MemberDefininition == predefined.MemberDefinition
@@ -934,9 +1086,9 @@ namespace Mono.CSharp
                        return Element.MemberDefinition.GetAttributeDefaultMember ();
                }
 
-               public MemberCache LoadMembers (TypeSpec declaringType)
+               public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
                {
-                       return Element.MemberDefinition.LoadMembers (declaringType);
+                       Element.MemberDefinition.LoadMembers (declaringType, onlyTypes, ref cache);
                }
 
                public bool IsImported {