Merge pull request #818 from hanswolff/patch-1
[mono.git] / mcs / mcs / pending.cs
index 3c9ef79a097b7f5ae94b55d3a291d7714fc66744..0f863a7bcf1c016f89a4588e49d6f427a5d7c676 100644 (file)
@@ -9,8 +9,10 @@
 //
 // Copyright 2001, 2002 Ximian, Inc (http://www.ximian.com)
 // Copyright 2003-2008 Novell, Inc.
+// Copyright 2011 Xamarin Inc
 //
 
+using System;
 using System.Collections.Generic;
 using System.Linq;
 
@@ -50,12 +52,84 @@ namespace Mono.CSharp {
                public MethodSpec [] need_proxy;
        }
 
+       struct ProxyMethodContext : IMemberContext
+       {
+               readonly TypeContainer container;
+
+               public ProxyMethodContext (TypeContainer container)
+               {
+                       this.container = container;
+               }
+
+               public TypeSpec CurrentType {
+                       get {
+                               throw new NotImplementedException ();
+                       }
+               }
+
+               public TypeParameters CurrentTypeParameters {
+                       get {
+                               throw new NotImplementedException ();
+                       }
+               }
+
+               public MemberCore CurrentMemberDefinition {
+                       get {
+                               throw new NotImplementedException ();
+                       }
+               }
+
+               public bool IsObsolete {
+                       get {
+                               return false;
+                       }
+               }
+
+               public bool IsUnsafe {
+                       get {
+                               throw new NotImplementedException ();
+                       }
+               }
+
+               public bool IsStatic {
+                       get {
+                               return false;
+                       }
+               }
+
+               public ModuleContainer Module {
+                       get {
+                               return container.Module;
+                       }
+               }
+
+               public string GetSignatureForError ()
+               {
+                       throw new NotImplementedException ();
+               }
+
+               public ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               public FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               public FullNamedExpression LookupNamespaceAlias (string name)
+               {
+                       throw new NotImplementedException ();
+               }
+       }
+
        public class PendingImplementation
        {
                /// <summary>
                ///   The container for this PendingImplementation
                /// </summary>
-               readonly TypeContainer container;
+               readonly TypeDefinition container;
                
                /// <summary>
                ///   This is the array of TypeAndMethods that describes the pending implementations
@@ -63,7 +137,7 @@ namespace Mono.CSharp {
                /// </summary>
                TypeAndMethods [] pending_implementations;
 
-               PendingImplementation (TypeContainer container, MissingInterfacesInfo[] missing_ifaces, MethodSpec[] abstract_methods, int total)
+               PendingImplementation (TypeDefinition container, MissingInterfacesInfo[] missing_ifaces, MethodSpec[] abstract_methods, int total)
                {
                        var type_builder = container.Definition;
                        
@@ -115,20 +189,20 @@ namespace Mono.CSharp {
 
                static readonly MissingInterfacesInfo [] EmptyMissingInterfacesInfo = new MissingInterfacesInfo [0];
                
-               static MissingInterfacesInfo [] GetMissingInterfaces (TypeContainer container)
+               static MissingInterfacesInfo [] GetMissingInterfaces (TypeDefinition container)
                {
                        //
-                       // Notice that Interfaces will only return the interfaces that the Type
-                       // is supposed to implement, not all the interfaces that the type implements.
+                       // Interfaces will return all interfaces that the container
+                       // implements including any inherited interfaces
                        //
                        var impl = container.Definition.Interfaces;
 
                        if (impl == null || impl.Count == 0)
                                return EmptyMissingInterfacesInfo;
 
-                       MissingInterfacesInfo[] ret = new MissingInterfacesInfo[impl.Count];
+                       var ret = new MissingInterfacesInfo[impl.Count];
 
-                       for (int i = 0; i < impl.Count; i++)
+                       for (int i = 0; i < ret.Length; i++)
                                ret [i] = new MissingInterfacesInfo (impl [i]);
 
                        // we really should not get here because Object doesnt implement any
@@ -159,7 +233,7 @@ namespace Mono.CSharp {
                // Register method implementations are either abstract methods
                // flagged as such on the base class or interface methods
                //
-               static public PendingImplementation GetPendingImplementations (TypeContainer container)
+               static public PendingImplementation GetPendingImplementations (TypeDefinition container)
                {
                        TypeSpec b = container.BaseType;
 
@@ -191,7 +265,73 @@ namespace Mono.CSharp {
                        if (total == 0)
                                return null;
 
-                       return new PendingImplementation (container, missing_interfaces, abstract_methods, total);
+                       var pending = new PendingImplementation (container, missing_interfaces, abstract_methods, total);
+
+                       //
+                       // check for inherited conflicting methods
+                       //
+                       foreach (var p in pending.pending_implementations) {
+                               //
+                               // It can happen for generic interfaces only
+                               //
+                               if (!p.type.IsGeneric)
+                                       continue;
+
+                               //
+                               // CLR does not distinguishes between ref and out
+                               //
+                               for (int i = 0; i < p.methods.Count; ++i) {
+                                       MethodSpec compared_method = p.methods[i];
+                                       if (compared_method.Parameters.IsEmpty)
+                                               continue;
+
+                                       for (int ii = i + 1; ii < p.methods.Count; ++ii) {
+                                               MethodSpec tested_method = p.methods[ii];
+                                               if (compared_method.Name != tested_method.Name)
+                                                       continue;
+
+                                               if (p.type != tested_method.DeclaringType)
+                                                       continue;
+
+                                               if (!TypeSpecComparer.Override.IsSame (compared_method.Parameters.Types, tested_method.Parameters.Types))
+                                                       continue;
+
+                                               bool exact_match = true;
+                                               bool ref_only_difference = false;
+                                               var cp = compared_method.Parameters.FixedParameters;
+                                               var tp = tested_method.Parameters.FixedParameters;
+
+                                               for (int pi = 0; pi < cp.Length; ++pi) {
+                                                       //
+                                                       // First check exact modifiers match
+                                                       //
+                                                       if ((cp[pi].ModFlags & Parameter.Modifier.RefOutMask) == (tp[pi].ModFlags & Parameter.Modifier.RefOutMask))
+                                                               continue;
+
+                                                       if (((cp[pi].ModFlags | tp[pi].ModFlags) & Parameter.Modifier.RefOutMask) == Parameter.Modifier.RefOutMask) {
+                                                               ref_only_difference = true;
+                                                               continue;
+                                                       }
+
+                                                       exact_match = false;
+                                                       break;
+                                               }
+
+                                               if (!exact_match || !ref_only_difference)
+                                                       continue;
+
+                                               pending.Report.SymbolRelatedToPreviousError (compared_method);
+                                               pending.Report.SymbolRelatedToPreviousError (tested_method);
+                                               pending.Report.Error (767, container.Location,
+                                                       "Cannot implement interface `{0}' with the specified type parameters because it causes method `{1}' to differ on parameter modifiers only",
+                                                       p.type.GetDefinition().GetSignatureForError (), compared_method.GetSignatureForError ());
+
+                                               break;
+                                       }
+                               }
+                       }
+
+                       return pending;
                }
 
                public enum Operation {
@@ -205,14 +345,14 @@ namespace Mono.CSharp {
                /// <summary>
                ///   Whether the specified method is an interface method implementation
                /// </summary>
-               public MethodSpec IsInterfaceMethod (MemberName name, TypeSpec ifaceType, MethodData method)
+               public MethodSpec IsInterfaceMethod (MemberName name, TypeSpec ifaceType, MethodData method, out MethodSpec ambiguousCandidate, ref bool optional)
                {
-                       return InterfaceMethod (name, ifaceType, method, Operation.Lookup);
+                       return InterfaceMethod (name, ifaceType, method, Operation.Lookup, out ambiguousCandidate, ref optional);
                }
 
-               public void ImplementMethod (MemberName name, TypeSpec ifaceType, MethodData method, bool clear_one
+               public void ImplementMethod (MemberName name, TypeSpec ifaceType, MethodData method, bool clear_one, out MethodSpec ambiguousCandidate, ref bool optional)
                {
-                       InterfaceMethod (name, ifaceType, method, clear_one ? Operation.ClearOne : Operation.ClearAll);
+                       InterfaceMethod (name, ifaceType, method, clear_one ? Operation.ClearOne : Operation.ClearAll, out ambiguousCandidate, ref optional);
                }
 
                /// <remarks>
@@ -232,21 +372,23 @@ namespace Mono.CSharp {
                ///   that was used in the interface, then we always need to create a proxy for it.
                ///
                /// </remarks>
-               public MethodSpec InterfaceMethod (MemberName name, TypeSpec iType, MethodData method, Operation op)
+               public MethodSpec InterfaceMethod (MemberName name, TypeSpec iType, MethodData method, Operation op, out MethodSpec ambiguousCandidate, ref bool optional)
                {
+                       ambiguousCandidate = null;
+
                        if (pending_implementations == null)
                                return null;
 
                        TypeSpec ret_type = method.method.ReturnType;
                        ParametersCompiled args = method.method.ParameterInfo;
                        bool is_indexer = method.method is Indexer.SetIndexerMethod || method.method is Indexer.GetIndexerMethod;
+                       MethodSpec m;
 
                        foreach (TypeAndMethods tm in pending_implementations){
                                if (!(iType == null || tm.type == iType))
                                        continue;
 
                                int method_count = tm.methods.Count;
-                               MethodSpec m;
                                for (int i = 0; i < method_count; i++){
                                        m = tm.methods [i];
 
@@ -281,6 +423,9 @@ namespace Mono.CSharp {
                                        // for an interface indexer).
                                        //
                                        if (op != Operation.Lookup) {
+                                               if (m.IsAccessor != method.method.IsAccessor)
+                                                       continue;
+
                                                // If `t != null', then this is an explicitly interface
                                                // implementation and we can always clear the method.
                                                // `need_proxy' is not null if we're implementing an
@@ -294,6 +439,12 @@ namespace Mono.CSharp {
                                                }
                                        } else {
                                                tm.found [i] = method;
+                                               optional = tm.optional;
+                                       }
+
+                                       if (op == Operation.Lookup && name.ExplicitInterface != null && ambiguousCandidate == null) {
+                                               ambiguousCandidate = m;
+                                               continue;
                                        }
 
                                        //
@@ -305,9 +456,12 @@ namespace Mono.CSharp {
 
                                // If a specific type was requested, we can stop now.
                                if (tm.type == iType)
-                                       return null;
+                                       break;
                        }
-                       return null;
+
+                       m = ambiguousCandidate;
+                       ambiguousCandidate = null;
+                       return m;
                }
 
                /// <summary>
@@ -353,10 +507,11 @@ namespace Mono.CSharp {
                        }
 
                        int top = param.Count;
-                       var ec = new EmitContext (null, proxy.GetILGenerator (), null);
+                       var ec = new EmitContext (new ProxyMethodContext (container), proxy.GetILGenerator (), null, null);
+                       ec.EmitThis ();
                        // TODO: GetAllParametersArguments
-                       for (int i = 0; i <= top; i++)
-                               ParameterReference.EmitLdArg (ec, i);
+                       for (int i = 0; i < top; i++)
+                               ec.EmitArgumentLoad (i);
 
                        ec.Emit (OpCodes.Call, base_method);
                        ec.Emit (OpCodes.Ret);
@@ -379,10 +534,14 @@ namespace Mono.CSharp {
                        // about mismatch at return type when the check bellow rejects them
                        //
                        var parameters = mi.Parameters;
+                       MethodSpec close_match = null;
+
                        while (true) {
                                var candidates = MemberCache.FindMembers (base_type, mi.Name, false);
-                               if (candidates == null)
+                               if (candidates == null) {
+                                       base_method = close_match;
                                        return false;
+                               }
 
                                MethodSpec similar_candidate = null;
                                foreach (var candidate in candidates) {
@@ -393,7 +552,7 @@ namespace Mono.CSharp {
                                                continue;
 
                                        var candidate_param = ((MethodSpec) candidate).Parameters;
-                                       if (!TypeSpecComparer.Override.IsEqualByRuntime (parameters, candidate_param))
+                                       if (!TypeSpecComparer.Override.IsEqual (parameters.Types, candidate_param.Types))
                                                continue;
 
                                        bool modifiers_match = true;
@@ -401,8 +560,7 @@ namespace Mono.CSharp {
                                                //
                                                // First check exact ref/out match
                                                //
-                                               const Parameter.Modifier ref_out = Parameter.Modifier.REF | Parameter.Modifier.OUT;
-                                               if ((parameters.FixedParameters[i].ModFlags & ref_out) == (candidate_param.FixedParameters[i].ModFlags & ref_out))
+                                               if ((parameters.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) == (candidate_param.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
                                                        continue;
 
                                                modifiers_match = false;
@@ -410,7 +568,7 @@ namespace Mono.CSharp {
                                                //
                                                // Different in ref/out only
                                                //
-                                               if ((parameters.FixedParameters[i].ModFlags & candidate_param.FixedParameters[i].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
+                                               if ((parameters.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (candidate_param.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask)) {
                                                        if (similar_candidate == null) {
                                                                if (!candidate.IsPublic)
                                                                        break;
@@ -433,18 +591,32 @@ namespace Mono.CSharp {
                                                continue;
 
                                        //
-                                       // From this point on the candidate is used for detailed error reporting
+                                       // From this point the candidate is used for detailed error reporting
                                        // because it's very close match to what we are looking for
                                        //
-                                       base_method = (MethodSpec) candidate;
+                                       var m = (MethodSpec) candidate;
 
-                                       if (!candidate.IsPublic)
-                                               return false;
+                                       if (!m.IsPublic) {
+                                               if (close_match == null)
+                                                       close_match = m;
 
-                                       if (!TypeSpecComparer.Override.IsEqual (mi.ReturnType, base_method.ReturnType))
-                                               return false;
-                               }
+                                               continue;
+                                       }
+
+                                       if (!TypeSpecComparer.Override.IsEqual (mi.ReturnType, m.ReturnType)) {
+                                               if (close_match == null)
+                                                       close_match = m;
+
+                                               continue;
+                                       }
+                                               
+                                       base_method = m;
 
+                                       if (mi.IsGeneric && !Method.CheckImplementingMethodConstraints (container, m, mi)) {
+                                               return true;
+                                       }
+                               }
+                               
                                if (base_method != null) {
                                        if (similar_candidate != null) {
                                                Report.SymbolRelatedToPreviousError (similar_candidate);
@@ -459,8 +631,10 @@ namespace Mono.CSharp {
                                }
 
                                base_type = candidates[0].DeclaringType.BaseType;
-                               if (base_type == null)
+                               if (base_type == null) {
+                                       base_method = close_match;
                                        return false;
+                               }
                        }
 
                        if (!base_method.IsVirtual) {
@@ -515,7 +689,7 @@ namespace Mono.CSharp {
                                                if (pending_implementations [i].optional)
                                                        continue;
 
-                                               MethodSpec candidate = null;
+                                               MethodSpec candidate;
                                                if (base_implements_type || BaseImplements (type, mi, out candidate))
                                                        continue;
 
@@ -531,16 +705,16 @@ namespace Mono.CSharp {
                                                        if (candidate.IsStatic) {
                                                                Report.Error (736, container.Location,
                                                                        "`{0}' does not implement interface member `{1}' and the best implementing candidate `{2}' is static",
-                                                                       container.GetSignatureForError (), mi.GetSignatureForError (), TypeManager.CSharpSignature (candidate));
+                                                                       container.GetSignatureForError (), mi.GetSignatureForError (), candidate.GetSignatureForError ());
                                                        } else if ((candidate.Modifiers & Modifiers.PUBLIC) == 0) {
                                                                Report.Error (737, container.Location,
-                                                                       "`{0}' does not implement interface member `{1}' and the best implementing candidate `{2}' in not public",
+                                                                       "`{0}' does not implement interface member `{1}' and the best implementing candidate `{2}' is not public",
                                                                        container.GetSignatureForError (), mi.GetSignatureForError (), candidate.GetSignatureForError ());
                                                        } else {
                                                                Report.Error (738, container.Location,
                                                                        "`{0}' does not implement interface member `{1}' and the best implementing candidate `{2}' return type `{3}' does not match interface member return type `{4}'",
-                                                                       container.GetSignatureForError (), mi.GetSignatureForError (), TypeManager.CSharpSignature (candidate),
-                                                                       TypeManager.CSharpName (candidate.ReturnType), TypeManager.CSharpName (mi.ReturnType));
+                                                                       container.GetSignatureForError (), mi.GetSignatureForError (), candidate.GetSignatureForError (),
+                                                                       candidate.ReturnType.GetSignatureForError (), mi.ReturnType.GetSignatureForError ());
                                                        }
                                                } else {
                                                        Report.Error (535, container.Location, "`{0}' does not implement interface member `{1}'",