Merge pull request #3867 from kumpera/issues
[mono.git] / mcs / mcs / membercache.cs
index 3837af2c2d8779e36d7cb82a064f3f5fbaeeb0e6..27b7f586932c7d01e355f5bc2745512d5cb07a1a 100644 (file)
@@ -354,7 +354,7 @@ namespace Mono.CSharp {
                //
                static bool AddInterfaceMember (MemberSpec member, ref IList<MemberSpec> existing)
                {
-                       var member_param = member is IParametersMember ? ((IParametersMember) member).Parameters : ParametersCompiled.EmptyReadOnlyParameters;
+                       var member_param = member is IParametersMember ? ((IParametersMember) member).Parameters : null;
 
                        //
                        // interface IA : IB { int Prop { set; } }
@@ -368,10 +368,14 @@ namespace Mono.CSharp {
                                if (entry.Arity != member.Arity)
                                        continue;
 
-                               if (entry is IParametersMember) {
-                                       var entry_param = ((IParametersMember) entry).Parameters;
-                                       if (!TypeSpecComparer.Override.IsEqual (entry_param, member_param))
-                                               continue;
+                               AParametersCollection entry_param = null;
+                               if (member_param != null) {
+                                       var entry_pm = entry as IParametersMember;
+                                       if (entry_pm != null) {
+                                               entry_param = entry_pm.Parameters;
+                                               if (!TypeSpecComparer.Override.IsEqual (entry_param, member_param))
+                                                       continue;
+                                       }
                                }
 
                                if (member.DeclaringType.ImplementsInterface (entry.DeclaringType, false)) {
@@ -384,8 +388,10 @@ namespace Mono.CSharp {
                                        continue;
                                }
 
-                               if ((entry.DeclaringType == member.DeclaringType && entry.IsAccessor == member.IsAccessor) ||
-                                       entry.DeclaringType.ImplementsInterface (member.DeclaringType, false))
+                               if ((entry.DeclaringType == member.DeclaringType && entry.IsAccessor == member.IsAccessor))
+                                       return false;
+
+                               if (entry.DeclaringType.ImplementsInterface (member.DeclaringType, false) && AParametersCollection.HasSameParameterDefaults (entry_param, member_param))
                                        return false;
                        }
 
@@ -400,8 +406,13 @@ namespace Mono.CSharp {
 
                public static MemberSpec FindMember (TypeSpec container, MemberFilter filter, BindingRestriction restrictions)
                {
+                       if (filter.Kind == MemberKind.Method && container.Kind == MemberKind.TypeParameter && filter.Parameters == null)
+                               throw new NotSupportedException ("type parameters methods cannot be lookup up due to two stage setup");
+
+                       IList<MemberSpec> applicable;
+                       var top_container = container;
+
                        do {
-                               IList<MemberSpec> applicable;
                                if (container.MemberCache.member_hash.TryGetValue (filter.Name, out applicable)) {
                                        // Start from the end because interface members are in reverse order
                                        for (int i = applicable.Count - 1; i >= 0; i--) {
@@ -432,6 +443,26 @@ namespace Mono.CSharp {
                                container = container.BaseType;
                        } while (container != null);
 
+                       var tps = top_container as TypeParameterSpec;
+                       if (tps != null && tps.InterfaceCache != null) {
+                               if (tps.InterfaceCache.member_hash.TryGetValue (filter.Name, out applicable)) {
+                                       for (int i = applicable.Count - 1; i >= 0; i--) {
+                                               var entry = applicable [i];
+
+                                               if ((restrictions & BindingRestriction.NoAccessors) != 0 && entry.IsAccessor)
+                                                       continue;
+
+                                               if ((restrictions & BindingRestriction.OverrideOnly) != 0 && (entry.Modifiers & Modifiers.OVERRIDE) == 0)
+                                                       continue;
+
+                                               if (!filter.Equals (entry))
+                                                       continue;
+
+                                               return entry;
+                                       }
+                               }
+                       }
+
                        return null;
                }
 
@@ -444,9 +475,9 @@ namespace Mono.CSharp {
                //
                public static IList<MemberSpec> FindMembers (TypeSpec container, string name, bool declaredOnlyClass)
                {
-                       IList<MemberSpec> applicable;
-
                        do {
+                               IList<MemberSpec> applicable;
+                               
                                if (container.MemberCache.member_hash.TryGetValue (name, out applicable) || declaredOnlyClass)
                                        return applicable;
 
@@ -456,10 +487,21 @@ namespace Mono.CSharp {
                        return null;
                }
 
+               public static IList<MemberSpec> FindInterfaceMembers (TypeParameterSpec typeParameter, string name)
+               {
+                       if (typeParameter.InterfaceCache != null) {
+                               IList<MemberSpec> applicable;
+                               typeParameter.InterfaceCache.member_hash.TryGetValue (name, out applicable);
+                               return applicable;
+                       }
+
+                       return null;
+               }
+
                //
                // Finds the nested type in container
                //
-               public static TypeSpec FindNestedType (TypeSpec container, string name, int arity)
+               public static TypeSpec FindNestedType (TypeSpec container, string name, int arity, bool declaredOnlyClass)
                {
                        IList<MemberSpec> applicable;
                        TypeSpec best_match = null;
@@ -488,7 +530,7 @@ namespace Mono.CSharp {
                                                if (arity < 0) {
                                                        if (best_match == null) {
                                                                best_match = ts;
-                                                       } else if (System.Math.Abs (ts.Arity + arity) < System.Math.Abs (ts.Arity + arity)) {
+                                                       } else if (System.Math.Abs (ts.Arity + arity) < System.Math.Abs (best_match.Arity + arity)) {
                                                                best_match = ts;
                                                        }
                                                }
@@ -496,7 +538,7 @@ namespace Mono.CSharp {
                                }
 
                                container = container.BaseType;
-                       } while (container != null);
+                       } while (container != null && !declaredOnlyClass);
 
                        return best_match;
                }
@@ -637,6 +679,24 @@ namespace Mono.CSharp {
                        return ambig_candidate;
                }
 
+               public static List<TypeSpec> GetDeclaredNestedTypes (TypeSpec container)
+               {
+                       List<TypeSpec> found = null;
+                       foreach (var entry in container.MemberCache.member_hash) {
+                               foreach (var member in entry.Value) {
+                                       if ((member.Kind & MemberKind.NestedMask) == 0)
+                                               continue;
+
+                                       if (found == null)
+                                               found = new List<TypeSpec> ();
+
+                                       found.Add ((TypeSpec)member);
+                               }
+                       }
+
+                       return found;
+               }
+
                //
                // Returns inflated version of MemberSpec, it works similarly to
                // SRE TypeBuilder.GetMethod
@@ -686,9 +746,10 @@ namespace Mono.CSharp {
                        throw new NotImplementedException (member.GetType ().ToString ());
                }
 
-               public static List<FieldSpec> GetAllFieldsForDefiniteAssignment (TypeSpec container)
+               public static List<FieldSpec> GetAllFieldsForDefiniteAssignment (TypeSpec container, IMemberContext context)
                {
                        List<FieldSpec> fields = null;
+                       bool imported = container.MemberDefinition.IsImported;
                        foreach (var entry in container.MemberCache.member_hash) {
                                foreach (var name_entry in entry.Value) {
                                        if (name_entry.Kind != MemberKind.Field)
@@ -704,13 +765,7 @@ namespace Mono.CSharp {
                                                continue;
 
                                        var fs = (FieldSpec) name_entry;
-
-                                       //
-                                       // LAMESPEC: Very bizzare hack, definitive assignment is not done
-                                       // for imported non-public reference fields except array. No idea what the
-                                       // actual csc rule is
-                                       //
-                                       if (!fs.IsPublic && container.MemberDefinition.IsImported && (!fs.MemberType.IsArray && TypeSpec.IsReferenceType (fs.MemberType)))
+                                       if (imported && ShouldIgnoreFieldForDefiniteAssignment (fs, context))
                                                continue;
 
                                        //if ((fs.Modifiers & (Modifiers.BACKING_FIELD) != 0)
@@ -727,6 +782,29 @@ namespace Mono.CSharp {
                        return fields ?? new List<FieldSpec> (0);
                }
 
+               static bool ShouldIgnoreFieldForDefiniteAssignment (FieldSpec fs, IMemberContext context)
+               {
+                       //
+                       // LAMESPEC: This mimics csc quirk where definitive assignment is not done
+                       // for all kinds of imported non-public struct fields
+                       //
+                       var mod = fs.Modifiers;
+                       if ((mod & Modifiers.PRIVATE) == 0 && ((mod & Modifiers.INTERNAL) != 0 && fs.DeclaringType.MemberDefinition.IsInternalAsPublic (context.Module.DeclaringAssembly)))
+                               return false;
+
+                       //
+                       // Ignore reference type fields except when type is an array or type parameter
+                       //
+                       var type = fs.MemberType;
+                       switch (type.Kind) {
+                       case MemberKind.ArrayType:
+                       case MemberKind.TypeParameter:
+                               return false;
+                       default:
+                               return TypeSpec.IsReferenceType (type);
+                       }
+               }
+
                public static IList<MemberSpec> GetCompletitionMembers (IMemberContext ctx, TypeSpec container, string name)
                {
                        var matches = new List<MemberSpec> ();
@@ -1298,7 +1376,7 @@ namespace Mono.CSharp {
                        if (a.DeclaringType.MemberDefinition != b.DeclaringType.MemberDefinition)
                                return mc_b;
 
-                       if (mc_a.Location.File != mc_a.Location.File)
+                       if (mc_a.Location.File != mc_b.Location.File)
                                return mc_b;
 
                        return mc_b.Location.Row > mc_a.Location.Row ? mc_b : mc_a;