[mcs] Initial by ref returns and variables support
[mono.git] / mcs / mcs / membercache.cs
index 7336f1dbf858ade6e732cba67fd63fba724eb364..eebf71b844b8e2a51337bf35a1560c7b13d7134f 100644 (file)
@@ -35,6 +35,7 @@ namespace Mono.CSharp {
                Enum            = 1 << 14,
                Interface       = 1 << 15,
                TypeParameter = 1 << 16,
+               ByRef           = 1 << 17,
 
                ArrayType = 1 << 19,
                PointerType = 1 << 20,
@@ -354,7 +355,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 +369,19 @@ 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 (entry.DeclaringType != member.DeclaringType) {
+                                                       if (!TypeSpecComparer.Override.IsEqual (entry_param, member_param))
+                                                               continue;
+                                               } else {
+                                                       if (!TypeSpecComparer.Equals (entry_param.Types, member_param.Types))
+                                                               continue;
+                                               }
+                                       }
                                }
 
                                if (member.DeclaringType.ImplementsInterface (entry.DeclaringType, false)) {
@@ -384,8 +394,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 +412,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 +449,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 +481,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 +493,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 +536,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 +544,7 @@ namespace Mono.CSharp {
                                }
 
                                container = container.BaseType;
-                       } while (container != null);
+                       } while (container != null && !declaredOnlyClass);
 
                        return best_match;
                }
@@ -637,6 +685,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 +752,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)
@@ -697,14 +764,6 @@ namespace Mono.CSharp {
                                        if ((name_entry.Modifiers & Modifiers.STATIC) != 0)
                                                continue;
 
-                                       //
-                                       // Ignore user private fields for definite assignment. This is sort of unexpected but
-                                       // rationale is to have consistent results when using reference assemblies which don't
-                                       // include any private fields and full assemblies
-                                       //
-                                       if ((name_entry.Modifiers & (Modifiers.PRIVATE | Modifiers.BACKING_FIELD)) == Modifiers.PRIVATE)
-                                               continue;
-
                                        //
                                        // Fixed size buffers are not subject to definite assignment checking
                                        //
@@ -712,13 +771,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)
@@ -735,6 +788,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> ();
@@ -954,6 +1030,7 @@ namespace Mono.CSharp {
                                                                                shared_list = false;
                                                                                prev = new List<MemberSpec> (found.Count + 1);
                                                                                prev.AddRange (found);
+                                                                               found = prev;
                                                                        } else {
                                                                                prev = (List<MemberSpec>) found;
                                                                        }
@@ -1306,7 +1383,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;
@@ -1425,6 +1502,12 @@ namespace Mono.CSharp {
                                                        }
                                                        return false;
                                                }
+
+                                               var pm_member = (MethodCore)member;
+                                               if (!NamedTupleSpec.CheckOverrideName (pm, pm_member) || !NamedTupleSpec.CheckOverrideName (pm.MemberType, pm_member.MemberType)) {
+                                                       Report.Error (8142, member.Location,
+                                                               "A partial method declaration and partial method implementation must both use the same tuple element names");
+                                               }
                                        }
                                }