Merge pull request #4380 from alexanderkyte/conflicting_attrs
[mono.git] / mcs / mcs / generic.cs
index fb7b6c79942278a404d2105f69c243ce1885d4e9..8ddef4f36947b630ee655efd11adbe80fa385b5c 100644 (file)
@@ -195,9 +195,7 @@ namespace Mono.CSharp {
                                        continue;
 
                                if (obsoleteCheck) {
-                                       ObsoleteAttribute obsolete_attr = t.GetAttributeObsolete ();
-                                       if (obsolete_attr != null)
-                                               AttributeTester.Report_ObsoleteMessage (obsolete_attr, t.GetSignatureForError (), c.Location, context.Module.Compiler.Report);
+                                       t.CheckObsoleteness (context, c.Location);
                                }
 
                                ConstraintChecker.Check (context, t, c.Location);
@@ -430,13 +428,13 @@ namespace Mono.CSharp {
                public TypeParameter (TypeParameterSpec spec, TypeSpec parentSpec, MemberName name, Attributes attrs)
                        : base (null, name, attrs)
                {
-                       this.spec = new TypeParameterSpec (parentSpec, spec.DeclaredPosition, spec.MemberDefinition, spec.SpecialConstraint, spec.Variance, null) {
+                       this.spec = new TypeParameterSpec (parentSpec, spec.DeclaredPosition, this, spec.SpecialConstraint, spec.Variance, null) {
                                BaseType = spec.BaseType,
                                InterfacesDefined = spec.InterfacesDefined,
                                TypeArguments = spec.TypeArguments
                        };
                }
-               
+
                #region Properties
 
                public override AttributeTargets AttributeTargets {
@@ -651,10 +649,10 @@ namespace Mono.CSharp {
                                var meta_constraints = new List<MetaType> (spec.TypeArguments.Length);
                                foreach (var c in spec.TypeArguments) {
                                        //
-                                       // Inflated type parameters can collide with special constraint types, don't
+                                       // Inflated type parameters can collide with base type constraint, don't
                                        // emit any such type parameter.
                                        //
-                                       if (c.BuiltinType == BuiltinTypeSpec.Type.Object || c.BuiltinType == BuiltinTypeSpec.Type.ValueType)
+                                       if (c.IsClass && spec.BaseType.BuiltinType != BuiltinTypeSpec.Type.Object)
                                                continue;
 
                                        meta_constraints.Add (c.GetMetaInfo ());
@@ -775,6 +773,7 @@ namespace Mono.CSharp {
                TypeSpec[] targs;
                TypeSpec[] ifaces_defined;
                TypeSpec effective_base;
+               MemberCache interface_cache;
 
                //
                // Creates type owned type parameter
@@ -884,6 +883,12 @@ namespace Mono.CSharp {
                        }
                }
 
+               public MemberCache InterfaceCache {
+                       get {
+                               return interface_cache;
+                       }
+               }
+
                //
                // Unexpanded interfaces list
                //
@@ -1114,14 +1119,20 @@ namespace Mono.CSharp {
                        //
                        bool found;
                        if (!TypeSpecComparer.Override.IsEqual (BaseType, other.BaseType)) {
-                               if (other.targs == null)
-                                       return false;
-
                                found = false;
-                               foreach (var otarg in other.targs) {
-                                       if (TypeSpecComparer.Override.IsEqual (BaseType, otarg)) {
-                                               found = true;
-                                               break;
+                               if (other.targs != null) {
+                                       foreach (var otarg in other.targs) {
+                                               if (TypeSpecComparer.Override.IsEqual (BaseType, otarg)) {
+                                                       found = true;
+                                                       break;
+                                               }
+                                       }
+                               } else if (targs != null) {
+                                       foreach (var targ in targs) {
+                                               if (TypeSpecComparer.Override.IsEqual (targ, other.BaseType)) {
+                                                       found = true;
+                                                       break;
+                                               }
                                        }
                                }
 
@@ -1134,7 +1145,7 @@ namespace Mono.CSharp {
                                //
                                // Iterate over inflated interfaces
                                //
-                               foreach (var iface in Interfaces) {
+                               foreach (var iface in InterfacesDefined) {
                                        found = false;
                                        if (other.InterfacesDefined != null) {
                                                foreach (var oiface in other.Interfaces) {
@@ -1164,18 +1175,25 @@ namespace Mono.CSharp {
 
                        // Check interfaces implementation <- definition
                        if (other.InterfacesDefined != null) {
-                               if (InterfacesDefined == null)
-                                       return false;
-
                                //
                                // Iterate over inflated interfaces
                                //
-                               foreach (var oiface in other.Interfaces) {
+                               foreach (var oiface in other.InterfacesDefined) {
                                        found = false;
-                                       foreach (var iface in Interfaces) {
-                                               if (TypeSpecComparer.Override.IsEqual (iface, oiface)) {
-                                                       found = true;
-                                                       break;
+
+                                       if (InterfacesDefined != null) {
+                                               foreach (var iface in Interfaces) {
+                                                       if (TypeSpecComparer.Override.IsEqual (iface, oiface)) {
+                                                               found = true;
+                                                               break;
+                                                       }
+                                               }
+                                       } else if (targs != null) {
+                                               foreach (var targ in targs) {
+                                                       if (TypeSpecComparer.Override.IsEqual (targ, oiface)) {
+                                                               found = true;
+                                                               break;
+                                                       }
                                                }
                                        }
 
@@ -1186,18 +1204,30 @@ namespace Mono.CSharp {
 
                        // Check type parameters implementation -> definition
                        if (targs != null) {
-                               if (other.targs == null)
-                                       return false;
-
                                foreach (var targ in targs) {
                                        found = false;
-                                       foreach (var otarg in other.targs) {
-                                               if (TypeSpecComparer.Override.IsEqual (targ, otarg)) {
-                                                       found = true;
-                                                       break;
+
+                                       if (other.targs != null) {
+                                               foreach (var otarg in other.targs) {
+                                                       if (TypeSpecComparer.Override.IsEqual (targ, otarg)) {
+                                                               found = true;
+                                                               break;
+                                                       }
+                                               }
+                                       }
+
+                                       if (other.InterfacesDefined != null && !found) {
+                                               foreach (var iface in other.Interfaces) {
+                                                       if (TypeSpecComparer.Override.IsEqual (iface, targ)) {
+                                                               found = true;
+                                                               break;
+                                                       }
                                                }
                                        }
 
+                                       if (!found)
+                                               found = TypeSpecComparer.Override.IsEqual (targ, other.BaseType);
+
                                        if (!found)
                                                return false;
                                }
@@ -1311,42 +1341,64 @@ namespace Mono.CSharp {
                {
                        cache = new MemberCache ();
 
+                       if (targs != null) {
+                               foreach (var ta in targs) {
+                                       var tps = ta as TypeParameterSpec;
+                                       var b_type = tps == null ? ta : tps.GetEffectiveBase ();
+
+                                       //
+                                       // Find the most specific type when base type was inflated from base constraints
+                                       //
+                                       if (b_type != null && !b_type.IsStructOrEnum && TypeSpec.IsBaseClass (b_type, BaseType, false))
+                                               BaseType = b_type;
+                               }
+                       }
+
                        //
                        // For a type parameter the membercache is the union of the sets of members of the types
                        // specified as a primary constraint or secondary constraint
                        //
-                       if (BaseType.BuiltinType != BuiltinTypeSpec.Type.Object && BaseType.BuiltinType != BuiltinTypeSpec.Type.ValueType)
+                       bool has_user_base_type = false;
+                       if (BaseType.BuiltinType != BuiltinTypeSpec.Type.Object && BaseType.BuiltinType != BuiltinTypeSpec.Type.ValueType) {
                                cache.AddBaseType (BaseType);
+                               has_user_base_type = true;
+                       }
 
                        if (InterfacesDefined != null) {
+                               var icache = cache;
+                               if (has_user_base_type) {
+                                       //
+                                       // type-parameter lookup rules are more complicated that other types lookup rules.
+                                       // Effective base class and its base types member have priority over interface
+                                       // constraints which means we cannot lookup interface members before class members
+                                       // hence we setup secondary cache for such cases.
+                                       //
+                                       interface_cache = new MemberCache ();
+                                       icache = interface_cache;
+                               }
+
                                foreach (var iface_type in InterfacesDefined) {
-                                       cache.AddInterface (iface_type);
+                                       icache.AddInterface (iface_type);
                                }
                        }
 
+                       //
+                       // Import interfaces after base type to match behavior from ordinary classes
+                       //
                        if (targs != null) {
                                foreach (var ta in targs) {
                                        var tps = ta as TypeParameterSpec;
-                                       IList<TypeSpec> ifaces;
-                                       TypeSpec b_type;
-                                       if (tps != null) {
-                                               b_type = tps.GetEffectiveBase ();
-                                               ifaces = tps.InterfacesDefined;
-                                       } else {
-                                               b_type = ta;
-                                               ifaces = ta.Interfaces;
-                                       }
-
-                                       //
-                                       // Don't add base type which was inflated from base constraints but it's not valid
-                                       // in C# context
-                                       //
-                                       if (b_type != null && b_type.BuiltinType != BuiltinTypeSpec.Type.Object && b_type.BuiltinType != BuiltinTypeSpec.Type.ValueType && !b_type.IsStructOrEnum)
-                                               cache.AddBaseType (b_type);
+                                       var ifaces = tps == null ? ta.Interfaces : tps.InterfacesDefined;
 
                                        if (ifaces != null) {
+                                               var icache = cache;
+                                               if (has_user_base_type) {
+                                                       interface_cache = new MemberCache ();
+                                                       icache = interface_cache;
+                                               }
+
                                                foreach (var iface_type in ifaces) {
-                                                       cache.AddInterface (iface_type);
+                                                       icache.AddInterface (iface_type);
                                                }
                                        }
                                }
@@ -1526,7 +1578,7 @@ namespace Mono.CSharp {
                                // Parent was inflated, find the same type on inflated type
                                // to use same cache for nested types on same generic parent
                                //
-                               type = MemberCache.FindNestedType (parent, type.Name, type.Arity);
+                               type = MemberCache.FindNestedType (parent, type.Name, type.Arity, false);
 
                                //
                                // Handle the tricky case where parent shares local type arguments
@@ -1915,6 +1967,14 @@ namespace Mono.CSharp {
                        return definition.GetMetaInfo ().MakeGenericType (all.ToArray ());
                }
 
+               public override void CheckObsoleteness (IMemberContext mc, Location loc)
+               {
+                       base.CheckObsoleteness (mc, loc);
+
+                       foreach (var ta in TypeArguments)
+                               ta.CheckObsoleteness (mc, loc);
+               }
+
                public override ObsoleteAttribute GetAttributeObsolete ()
                {
                        return open_type.GetAttributeObsolete ();
@@ -2102,6 +2162,10 @@ namespace Mono.CSharp {
                                return this;
 
                        var mutated = (InflatedTypeSpec) MemberwiseClone ();
+#if DEBUG
+                       mutated.ID += 1000000;
+#endif
+
                        if (decl != DeclaringType) {
                                // Gets back MethodInfo in case of metaInfo was inflated
                                //mutated.info = MemberCache.GetMember<TypeSpec> (DeclaringType.GetDefinition (), this).info;
@@ -3078,21 +3142,36 @@ namespace Mono.CSharp {
                                return ExactInference (ac_u.Element, ac_v.Element);
                        }
 
-                       // If V is constructed type and U is constructed type
+                       //
+                       // If V is constructed type and U is constructed type or dynamic
+                       //
                        if (TypeManager.IsGenericType (v)) {
-                               if (!TypeManager.IsGenericType (u) || v.MemberDefinition != u.MemberDefinition)
-                                       return 0;
+                               if (u.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
 
-                               TypeSpec [] ga_u = TypeManager.GetTypeArguments (u);
-                               TypeSpec [] ga_v = TypeManager.GetTypeArguments (v);
-                               if (ga_u.Length != ga_v.Length)
-                                       return 0;
+                                       var ga_v = v.TypeArguments;
+
+                                       int score = 0;
+                                       for (int i = 0; i < ga_v.Length; ++i)
+                                               score += ExactInference (u, ga_v [i]);
+
+                                       return System.Math.Min (1, score);
+
+                               } else {
+                                       if (!TypeManager.IsGenericType (u) || v.MemberDefinition != u.MemberDefinition)
+                                               return 0;
+
+                                       var ga_u = u.TypeArguments;
+                                       var ga_v = v.TypeArguments;
+
+                                       if (u.TypeArguments.Length != v.TypeArguments.Length)
+                                               return 0;
 
-                               int score = 0;
-                               for (int i = 0; i < ga_u.Length; ++i)
-                                       score += ExactInference (ga_u [i], ga_v [i]);
+                                       int score = 0;
+                                       for (int i = 0; i < ga_v.Length; ++i)
+                                               score += ExactInference (ga_u [i], ga_v [i]);
 
-                               return System.Math.Min (1, score);
+                                       return System.Math.Min (1, score);
+                               }
                        }
 
                        // If V is one of the unfixed type arguments