Don't emit reaonly. prefix for reference loads
[mono.git] / mcs / mcs / pending.cs
index d859ffdd2070bec9bc97cfb504fb6492cb7afbea..696797aa01f3ff4346a6d6159c1a3cec68ded53e 100644 (file)
@@ -1,25 +1,33 @@
 //
 // pending.cs: Pending method implementation
 //
-// Author:
+// Authors:
 //   Miguel de Icaza (miguel@gnu.org)
+//   Marek Safar (marek.safar@gmail.com)
 //
-// Licensed under the terms of the GNU GPL
-//
-// (C) 2001, 2002 Ximian, Inc (http://www.ximian.com)
+// Dual licensed under the terms of the MIT X11 or GNU GPL
 //
+// Copyright 2001, 2002 Ximian, Inc (http://www.ximian.com)
+// Copyright 2003-2008 Novell, Inc.
 //
 
 using System;
-using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+
+#if STATIC
+using IKVM.Reflection;
+using IKVM.Reflection.Emit;
+#else
 using System.Reflection;
 using System.Reflection.Emit;
+#endif
 
 namespace Mono.CSharp {
 
        struct TypeAndMethods {
-               public Type          type;
-               public MethodInfo [] methods;
+               public TypeSpec          type;
+               public IList<MethodSpec> methods;
 
                // 
                // Whether it is optional, this is used to allow the explicit/implicit
@@ -30,262 +38,118 @@ namespace Mono.CSharp {
                // class X : IA { }  class Y : X, IA { IA.Explicit (); }
                //
                public bool          optional;
-               
-               // Far from ideal, but we want to avoid creating a copy
-               // of methods above.
-               public Type [][]     args;
-
-               //This is used to store the modifiers of arguments
-               public Parameter.Modifier [][] mods;
-               
+                               
                //
                // This flag on the method says `We found a match, but
                // because it was private, we could not use the match
                //
-               public bool []       found;
+               public MethodData [] found;
 
                // If a method is defined here, then we always need to
                // create a proxy for it.  This is used when implementing
                // an interface's indexer with a different IndexerName.
-               public MethodInfo [] need_proxy;
-
-               //
-               // The name of the indexer (if it exists), precompute set/get, because
-               // they would be recomputed many times inside a loop later on.
-               //
-               public string set_indexer_name;
-               public string get_indexer_name;
+               public MethodSpec [] need_proxy;
        }
 
-       public class PendingImplementation {
+       public class PendingImplementation
+       {
                /// <summary>
                ///   The container for this PendingImplementation
                /// </summary>
-               TypeContainer container;
+               readonly TypeContainer container;
                
-               /// <summary>
-               ///   This filter is used by FindMembers, and it is used to
-               ///   extract only virtual/abstract fields
-               /// </summary>
-               static MemberFilter virtual_method_filter;
-
                /// <summary>
                ///   This is the array of TypeAndMethods that describes the pending implementations
                ///   (both interfaces and abstract methods in base class)
                /// </summary>
                TypeAndMethods [] pending_implementations;
 
-               static bool IsVirtualFilter (MemberInfo m, object filterCriteria)
+               PendingImplementation (TypeContainer container, MissingInterfacesInfo[] missing_ifaces, MethodSpec[] abstract_methods, int total)
                {
-                       MethodInfo mi = m as MethodInfo;
-                       return (mi == null) ? false : mi.IsVirtual;
-               }
-
-               /// <summary>
-               ///   Inits the virtual_method_filter
-               /// </summary>
-               static PendingImplementation ()
-               {
-                       virtual_method_filter = new MemberFilter (IsVirtualFilter);
-               }
-
-               // <remarks>
-               //   Returns a list of the abstract methods that are exposed by all of our
-               //   bases that we must implement.  Notice that this `flattens' the
-               //   method search space, and takes into account overrides.  
-               // </remarks>
-               static ArrayList GetAbstractMethods (Type t)
-               {
-                       ArrayList list = null;
-                       bool searching = true;
-                       Type current_type = t;
-                       
-                       do {
-                               MemberList mi;
-                               
-                               mi = TypeContainer.FindMembers (
-                                       current_type, MemberTypes.Method,
-                                       BindingFlags.Public | BindingFlags.NonPublic |
-                                       BindingFlags.Instance | BindingFlags.DeclaredOnly,
-                                       virtual_method_filter, null);
-
-                               if (current_type == TypeManager.object_type)
-                                       searching = false;
-                               else {
-                                       current_type = current_type.BaseType;
-                                       if (!current_type.IsAbstract)
-                                               searching = false;
-                               }
-
-                               if (mi.Count == 0)
-                                       continue;
-
-                               if (mi.Count == 1 && !(mi [0] is MethodBase))
-                                       searching = false;
-                               else 
-                                       list = TypeManager.CopyNewMethods (list, mi);
-                       } while (searching);
-
-                       if (list == null)
-                               return null;
-                       
-                       for (int i = 0; i < list.Count; i++){
-                               while (list.Count > i && !((MethodInfo) list [i]).IsAbstract)
-                                       list.RemoveAt (i);
-                       }
-
-                       if (list.Count == 0)
-                               return null;
-
-                       return list;
-               }
-
-               PendingImplementation (TypeContainer container, MissingInterfacesInfo [] missing_ifaces, ArrayList abstract_methods, int total)
-               {
-                       TypeBuilder type_builder = container.TypeBuilder;
+                       var type_builder = container.Definition;
                        
                        this.container = container;
                        pending_implementations = new TypeAndMethods [total];
 
                        int i = 0;
-                       foreach (MissingInterfacesInfo missing in missing_ifaces){
-                               MethodInfo [] mi;
-                               Type t = missing.Type;
+                       if (abstract_methods != null) {
+                               int count = abstract_methods.Length;
+                               pending_implementations [i].methods = new MethodSpec [count];
+                               pending_implementations [i].need_proxy = new MethodSpec [count];
 
-                               if (!t.IsInterface)
-                                       continue;
-
-                               if (t is TypeBuilder){
-                                       TypeContainer iface;
-
-                                       iface = TypeManager.LookupInterface (t);
+                               pending_implementations [i].methods = abstract_methods;
+                               pending_implementations [i].found = new MethodData [count];
+                               pending_implementations [i].type = type_builder;
+                               ++i;
+                       }
 
-                                       mi = iface.GetMethods ();
-                               } else 
-                                       mi = t.GetMethods ();
+                       foreach (MissingInterfacesInfo missing in missing_ifaces) {
+                               var iface = missing.Type;
+                               var mi = MemberCache.GetInterfaceMethods (iface);
 
-                               int count = mi.Length;
-                               pending_implementations [i].type = t;
+                               int count = mi.Count;
+                               pending_implementations [i].type = iface;
                                pending_implementations [i].optional = missing.Optional;
                                pending_implementations [i].methods = mi;
-                               pending_implementations [i].args = new Type [count][];
-                               pending_implementations [i].mods = new Parameter.Modifier [count][];
-                               pending_implementations [i].found = new bool [count];
-                               pending_implementations [i].need_proxy = new MethodInfo [count];
-                               string indexer_name = TypeManager.IndexerPropertyName (t);
-
-                               pending_implementations [i].set_indexer_name = "set_" + indexer_name;
-                               pending_implementations [i].get_indexer_name = "get_" + indexer_name;
-                               
-                               int j = 0;
-                               foreach (MethodInfo m in mi){
-                                       pending_implementations [i].args [j] = TypeManager.NoTypes;
-                                       pending_implementations [i].mods [j] = null;
-
-                                       // If there is a previous error, just ignore
-                                       if (m == null)
-                                               continue;
-
-                                       ParameterData pd = TypeManager.GetParameterData (m);
-                                       pending_implementations [i].args [j] = pd.Types;
-                                       
-                                       if (pd.Count > 0){
-                                               Parameter.Modifier [] pm = new Parameter.Modifier [pd.Count];
-                                               for (int k = 0; k < pd.Count; k++)
-                                                       pm [k] = pd.ParameterModifier (k);
-                                               pending_implementations [i].mods [j] = pm;
-                                       }
-                       
-                                       j++;
-                               }
+                               pending_implementations [i].found = new MethodData [count];
+                               pending_implementations [i].need_proxy = new MethodSpec [count];
                                i++;
                        }
+               }
 
-                       if (abstract_methods != null){
-                               int count = abstract_methods.Count;
-                               pending_implementations [i].methods = new MethodInfo [count];
-                               pending_implementations [i].need_proxy = new MethodInfo [count];
-                               
-                               abstract_methods.CopyTo (pending_implementations [i].methods, 0);
-                               pending_implementations [i].found = new bool [count];
-                               pending_implementations [i].args = new Type [count][];
-                               pending_implementations [i].mods = new Parameter.Modifier [count][];
-                               pending_implementations [i].type = type_builder;
-
-                               string indexer_name = TypeManager.IndexerPropertyName (type_builder);
-                               pending_implementations [i].set_indexer_name = "set_" + indexer_name;
-                               pending_implementations [i].get_indexer_name = "get_" + indexer_name;
-                               
-                               int j = 0;
-                               foreach (MemberInfo m in abstract_methods){
-                                       MethodInfo mi = (MethodInfo) m;
-                                       
-                                       ParameterData pd = TypeManager.GetParameterData (mi);
-                                       Type [] types = pd.Types;
-                                       
-                                       pending_implementations [i].args [j] = types;
-                                       pending_implementations [i].mods [j] = null;
-                                       if (pd.Count > 0){
-                                               Parameter.Modifier [] pm = new Parameter.Modifier [pd.Count];
-                                               for (int k = 0; k < pd.Count; k++)
-                                                       pm [k] = pd.ParameterModifier (k);
-                                               pending_implementations [i].mods [j] = pm;
-                                       }
-                                               
-                                       j++;
-                               }
+               Report Report {
+                       get {
+                               return container.Module.Compiler.Report;
                        }
                }
 
                struct MissingInterfacesInfo {
-                       public Type Type;
+                       public TypeSpec Type;
                        public bool Optional;
 
-                       public MissingInterfacesInfo (Type t)
+                       public MissingInterfacesInfo (TypeSpec t)
                        {
                                Type = t;
                                Optional = false;
                        }
                }
 
-               static MissingInterfacesInfo [] EmptyMissingInterfacesInfo = new MissingInterfacesInfo [0];
+               static readonly MissingInterfacesInfo [] EmptyMissingInterfacesInfo = new MissingInterfacesInfo [0];
                
-               static MissingInterfacesInfo [] GetMissingInterfaces (TypeBuilder type_builder)
+               static MissingInterfacesInfo [] GetMissingInterfaces (TypeContainer container)
                {
                        //
-                       // Notice that TypeBuilders will only return the interfaces that the Type
+                       // Notice that Interfaces will only return the interfaces that the Type
                        // is supposed to implement, not all the interfaces that the type implements.
                        //
-                       // Even better -- on MS it returns an empty array, no matter what.
-                       //
-                       // Completely broken.  So we do it ourselves!
-                       //
-                       Type [] impl = TypeManager.GetExplicitInterfaces (type_builder);
+                       var impl = container.Definition.Interfaces;
 
-                       if (impl == null || impl.Length == 0)
+                       if (impl == null || impl.Count == 0)
                                return EmptyMissingInterfacesInfo;
 
-                       MissingInterfacesInfo [] ret = new MissingInterfacesInfo [impl.Length];
+                       MissingInterfacesInfo[] ret = new MissingInterfacesInfo[impl.Count];
 
-                       for (int i = 0; i < impl.Length; i++)
+                       for (int i = 0; i < impl.Count; i++)
                                ret [i] = new MissingInterfacesInfo (impl [i]);
-                       
+
                        // we really should not get here because Object doesnt implement any
                        // interfaces. But it could implement something internal, so we have
                        // to handle that case.
-                       if (type_builder.BaseType == null)
+                       if (container.BaseType == null)
                                return ret;
                        
-                       Type [] base_impls = TypeManager.GetInterfaces (type_builder.BaseType);
-                       
-                       foreach (Type t in base_impls) {
-                               for (int i = 0; i < ret.Length; i ++) {
-                                       if (t == ret [i].Type) {
-                                               ret [i].Optional = true;
-                                               break;
+                       var base_impls = container.BaseType.Interfaces;
+                       if (base_impls != null) {
+                               foreach (TypeSpec t in base_impls) {
+                                       for (int i = 0; i < ret.Length; i++) {
+                                               if (t == ret[i].Type) {
+                                                       ret[i].Optional = true;
+                                                       break;
+                                               }
                                        }
                                }
                        }
+
                        return ret;
                }
                
@@ -298,11 +162,9 @@ namespace Mono.CSharp {
                //
                static public PendingImplementation GetPendingImplementations (TypeContainer container)
                {
-                       TypeBuilder type_builder = container.TypeBuilder;
-                       MissingInterfacesInfo [] missing_interfaces;
-                       Type b = type_builder.BaseType;
+                       TypeSpec b = container.BaseType;
 
-                       missing_interfaces = GetMissingInterfaces (type_builder);
+                       var missing_interfaces = GetMissingInterfaces (container);
 
                        //
                        // If we are implementing an abstract class, and we are not
@@ -312,21 +174,92 @@ namespace Mono.CSharp {
                        //
                        // We also pre-compute the methods.
                        //
-                       bool implementing_abstract = ((b != null) && b.IsAbstract && !type_builder.IsAbstract);
-                       ArrayList abstract_methods = null;
+                       bool implementing_abstract = ((b != null) && b.IsAbstract && (container.ModFlags & Modifiers.ABSTRACT) == 0);
+                       MethodSpec[] abstract_methods = null;
 
                        if (implementing_abstract){
-                               abstract_methods = GetAbstractMethods (b);
-                               
-                               if (abstract_methods == null)
+                               var am = MemberCache.GetNotImplementedAbstractMethods (b);
+
+                               if (am == null) {
                                        implementing_abstract = false;
+                               } else {
+                                       abstract_methods = new MethodSpec[am.Count];
+                                       am.CopyTo (abstract_methods, 0);
+                               }
                        }
                        
                        int total = missing_interfaces.Length +  (implementing_abstract ? 1 : 0);
                        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
+                                                       //
+                                                       const Parameter.Modifier ref_out = Parameter.Modifier.REF | Parameter.Modifier.OUT;
+                                                       if ((cp[pi].ModFlags & ref_out) == (tp[pi].ModFlags & ref_out))
+                                                               continue;
+
+                                                       if ((cp[pi].ModFlags & tp[pi].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
+                                                               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 {
@@ -340,28 +273,16 @@ namespace Mono.CSharp {
                /// <summary>
                ///   Whether the specified method is an interface method implementation
                /// </summary>
-               public MethodInfo IsInterfaceMethod (Type t, string name, Type ret_type, ParameterData args)
+               public MethodSpec IsInterfaceMethod (MemberName name, TypeSpec ifaceType, MethodData method, out MethodSpec ambiguousCandidate)
                {
-                       return InterfaceMethod (t, name, ret_type, args, Operation.Lookup, null);
+                       return InterfaceMethod (name, ifaceType, method, Operation.Lookup, out ambiguousCandidate);
                }
 
-               public MethodInfo IsInterfaceIndexer (Type t, Type ret_type, ParameterData args)
+               public void ImplementMethod (MemberName name, TypeSpec ifaceType, MethodData method, bool clear_one, out MethodSpec ambiguousCandidate)
                {
-                       return InterfaceMethod (t, null, ret_type, args, Operation.Lookup, null);
+                       InterfaceMethod (name, ifaceType, method, clear_one ? Operation.ClearOne : Operation.ClearAll, out ambiguousCandidate);
                }
 
-               public void ImplementMethod (Type t, string name, Type ret_type, ParameterData args, bool clear_one) 
-               {
-                       InterfaceMethod (t, name, ret_type, args,
-                                        clear_one ? Operation.ClearOne : Operation.ClearAll, null);
-               }
-
-               public void ImplementIndexer (Type t, MethodInfo mi, Type ret_type, ParameterData args, bool clear_one) 
-               {
-                       InterfaceMethod (t, null, ret_type, args,
-                                        clear_one ? Operation.ClearOne : Operation.ClearAll, mi);
-               }
-               
                /// <remarks>
                ///   If a method in Type `t' (or null to look in all interfaces
                ///   and the base abstract class) with name `Name', return type `ret_type' and
@@ -379,26 +300,48 @@ namespace Mono.CSharp {
                ///   that was used in the interface, then we always need to create a proxy for it.
                ///
                /// </remarks>
-               public MethodInfo InterfaceMethod (Type t, string name, Type ret_type, ParameterData args,
-                                                  Operation op, MethodInfo need_proxy)
+               public MethodSpec InterfaceMethod (MemberName name, TypeSpec iType, MethodData method, Operation op, out MethodSpec ambiguousCandidate)
                {
-                       int arg_len = args.Count;
+                       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 (!(t == null || tm.type == t))
+                               if (!(iType == null || tm.type == iType))
                                        continue;
 
-                               int method_count = tm.methods.Length;
-                               MethodInfo m;
+                               int method_count = tm.methods.Count;
                                for (int i = 0; i < method_count; i++){
                                        m = tm.methods [i];
 
                                        if (m == null)
                                                continue;
 
+                                       if (is_indexer) {
+                                               if (!m.IsAccessor || m.Parameters.IsEmpty)
+                                                       continue;
+                                       } else {
+                                               if (name.Name != m.Name)
+                                                       continue;
+
+                                               if (m.Arity != name.Arity)
+                                                       continue;
+                                       }
+
+                                       if (!TypeSpecComparer.Override.IsEqual (m.Parameters, args))
+                                               continue;
+
+                                       if (!TypeSpecComparer.Override.IsEqual (m.ReturnType, ret_type)) {
+                                               tm.found[i] = method;
+                                               continue;
+                                       }
+
                                        //
                                        // `need_proxy' is not null when we're implementing an
                                        // interface indexer and this is Clear(One/All) operation.
@@ -407,60 +350,29 @@ namespace Mono.CSharp {
                                        // signature and not on the name (this is done in the Lookup
                                        // for an interface indexer).
                                        //
-                                       if (name == null){
-                                               if (m.Name != tm.get_indexer_name && m.Name != tm.set_indexer_name)
+                                       if (op != Operation.Lookup) {
+                                               if (m.IsAccessor != method.method.IsAccessor)
                                                        continue;
-                                       } else if ((need_proxy == null) && (name != m.Name))
-                                               continue;
-
-                                       if (ret_type != m.ReturnType &&
-                                           !(ret_type == null && m.ReturnType == TypeManager.void_type) &&
-                                           !(m.ReturnType == null && ret_type == TypeManager.void_type))
-                                               continue;
 
-                                       //
-                                       // Check if we have the same parameters
-                                       //
-
-                                       if (tm.args [i] == null && arg_len != 0)
-                                               continue;
-                                       if (tm.args [i] != null && tm.args [i].Length != arg_len)
-                                               continue;
-
-                                       int j;
-
-                                       for (j = 0; j < arg_len; j++) {
-                                               if (tm.args [i][j] != args.ParameterType (j))
-                                                       break;
-                                               if (tm.mods [i][j] == args.ParameterModifier (j))
-                                                       continue;
-                                               // The modifiers are different, but if one of them
-                                               // is a PARAMS modifier, and the other isn't, ignore
-                                               // the difference.
-                                               if (tm.mods [i][j] != Parameter.Modifier.PARAMS &&
-                                                   args.ParameterModifier (j) != Parameter.Modifier.PARAMS)
-                                                       break;
-                                       }
-                                       if (j != arg_len)
-                                               continue;
-
-                                       if (op != Operation.Lookup){
                                                // 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
                                                // interface indexer.  In this case, we need to create
                                                // a proxy if the implementation's IndexerName doesn't
                                                // match the IndexerName in the interface.
-                                               bool name_matches = false;
-                                               if (name == m.Name || m.Name == tm.get_indexer_name || m.Name == tm.set_indexer_name)
-                                                       name_matches = true;
-                                               
-                                               if ((t == null) && (need_proxy != null) && !name_matches)
-                                                       tm.need_proxy [i] = need_proxy;
-                                               else 
-                                                       tm.methods [i] = null;
+                                               if (m.DeclaringType.IsInterface && iType == null && name.Name != m.Name) {      // TODO: This is very expensive comparison
+                                                       tm.need_proxy[i] = method.method.Spec;
+                                               } else {
+                                                       tm.methods[i] = null;
+                                               }
+                                       } else {
+                                               tm.found [i] = method;
+                                       }
+
+                                       if (op == Operation.Lookup && name.Left != null && ambiguousCandidate == null) {
+                                               ambiguousCandidate = m;
+                                               continue;
                                        }
-                                       tm.found [i] = true;
 
                                        //
                                        // Lookups and ClearOne return
@@ -470,10 +382,13 @@ namespace Mono.CSharp {
                                }
 
                                // If a specific type was requested, we can stop now.
-                               if (tm.type == t)
-                                       return null;
+                               if (tm.type == iType)
+                                       break;
                        }
-                       return null;
+
+                       m = ambiguousCandidate;
+                       ambiguousCandidate = null;
+                       return m;
                }
 
                /// <summary>
@@ -485,31 +400,49 @@ namespace Mono.CSharp {
                ///   For that case, we create an explicit implementation function
                ///   I.M in Y.
                /// </summary>
-               void DefineProxy (Type iface, MethodInfo base_method, MethodInfo iface_method,
-                                 Type [] args)
+               void DefineProxy (TypeSpec iface, MethodSpec base_method, MethodSpec iface_method)
                {
-                       MethodBuilder proxy;
+                       // TODO: Handle nested iface names
+                       string proxy_name;
+                       var ns = iface.MemberDefinition.Namespace;
+                       if (string.IsNullOrEmpty (ns))
+                               proxy_name = iface.MemberDefinition.Name + "." + iface_method.Name;
+                       else
+                               proxy_name = ns + "." + iface.MemberDefinition.Name + "." + iface_method.Name;
 
-                       string proxy_name = iface.Name + "." + iface_method.Name;
+                       var param = iface_method.Parameters;
 
-                       proxy = container.TypeBuilder.DefineMethod (
+                       MethodBuilder proxy = container.TypeBuilder.DefineMethod (
                                proxy_name,
+                               MethodAttributes.Private |
                                MethodAttributes.HideBySig |
                                MethodAttributes.NewSlot |
-                               MethodAttributes.Virtual,
+                               MethodAttributes.CheckAccessOnOverride |
+                               MethodAttributes.Virtual | MethodAttributes.Final,
                                CallingConventions.Standard | CallingConventions.HasThis,
-                               base_method.ReturnType, args);
+                               base_method.ReturnType.GetMetaInfo (), param.GetMetaInfo ());
 
-                       int top = args.Length;
-                       ILGenerator ig = proxy.GetILGenerator ();
+                       if (iface_method.IsGeneric) {
+                               var gnames = iface_method.GenericDefinition.TypeParameters.Select (l => l.Name).ToArray ();
+                               proxy.DefineGenericParameters (gnames);
+                       }
 
+                       for (int i = 0; i < param.Count; i++) {
+                               string name = param.FixedParameters [i].Name;
+                               ParameterAttributes attr = ParametersCompiled.GetParameterAttribute (param.FixedParameters [i].ModFlags);
+                               proxy.DefineParameter (i + 1, attr, name);
+                       }
+
+                       int top = param.Count;
+                       var ec = new EmitContext (null, proxy.GetILGenerator (), null);
+                       // TODO: GetAllParametersArguments
                        for (int i = 0; i <= top; i++)
-                               ParameterReference.EmitLdArg (ig, i);
+                               ParameterReference.EmitLdArg (ec, i);
 
-                       ig.Emit (OpCodes.Call, base_method);
-                       ig.Emit (OpCodes.Ret);
+                       ec.Emit (OpCodes.Call, base_method);
+                       ec.Emit (OpCodes.Ret);
 
-                       container.TypeBuilder.DefineMethodOverride (proxy, iface_method);
+                       container.TypeBuilder.DefineMethodOverride (proxy, (MethodInfo) iface_method.GetMetaInfo ());
                }
                
                /// <summary>
@@ -517,32 +450,114 @@ namespace Mono.CSharp {
                ///   the given method (which turns out, it is valid to have an interface
                ///   implementation in a base
                /// </summary>
-               bool BaseImplements (Type iface_type, MethodInfo mi)
+               bool BaseImplements (TypeSpec iface_type, MethodSpec mi, out MethodSpec base_method)
                {
-                       MethodSignature ms;
-                       
-                       Type [] args = TypeManager.GetParameterData (mi).Types;
-                       ms = new MethodSignature (mi.Name, mi.ReturnType, args);
-                       MemberList list = TypeContainer.FindMembers (
-                               container.TypeBuilder.BaseType, MemberTypes.Method | MemberTypes.Property,
-                               BindingFlags.Public | BindingFlags.Instance,
-                               MethodSignature.method_signature_filter, ms);
-
-                       if (list.Count == 0)
-                               return false;
-
-                       if (TypeManager.ImplementsInterface (container.TypeBuilder.BaseType, iface_type))
-                               return true;
+                       base_method = null;
+                       var base_type = container.BaseType;
 
                        //
-                       // FIXME: We should be creating fewer proxies.  The runtime can handle most cases.  
-                       //        At worst, if we can't avoid creating the proxy, we may need to make the 
-                       //        proxy use Callvirt.
+                       // Setup filter with no return type to give better error message
+                       // about mismatch at return type when the check bellow rejects them
                        //
-                       MethodInfo base_method = (MethodInfo) list [0];
+                       var parameters = mi.Parameters;
+                       while (true) {
+                               var candidates = MemberCache.FindMembers (base_type, mi.Name, false);
+                               if (candidates == null)
+                                       return false;
+
+                               MethodSpec similar_candidate = null;
+                               foreach (var candidate in candidates) {
+                                       if (candidate.Kind != MemberKind.Method)
+                                               continue;
+
+                                       if (candidate.Arity != mi.Arity)
+                                               continue;
+
+                                       var candidate_param = ((MethodSpec) candidate).Parameters;
+                                       if (!TypeSpecComparer.Override.IsSame (parameters.Types, candidate_param.Types))
+                                               continue;
+
+                                       bool modifiers_match = true;
+                                       for (int i = 0; i < parameters.Count; ++i) {
+                                               //
+                                               // 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))
+                                                       continue;
+
+                                               modifiers_match = false;
+
+                                               //
+                                               // Different in ref/out only
+                                               //
+                                               if ((parameters.FixedParameters[i].ModFlags & candidate_param.FixedParameters[i].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
+                                                       if (similar_candidate == null) {
+                                                               if (!candidate.IsPublic)
+                                                                       break;
+
+                                                               if (!TypeSpecComparer.Override.IsEqual (mi.ReturnType, ((MethodSpec) candidate).ReturnType))
+                                                                       break;
+
+                                                               // It's used for ref/out ambiguity overload check
+                                                               similar_candidate = (MethodSpec) candidate;
+                                                       }
+
+                                                       continue;
+                                               }
+
+                                               similar_candidate = null;
+                                               break;
+                                       }
+
+                                       if (!modifiers_match)
+                                               continue;
+
+                                       //
+                                       // From this point on the candidate is used for detailed error reporting
+                                       // because it's very close match to what we are looking for
+                                       //
+                                       base_method = (MethodSpec) candidate;
 
-                       if (!base_method.IsAbstract && !base_method.IsVirtual)
-                               DefineProxy (iface_type, base_method, mi, args);
+                                       if (!candidate.IsPublic)
+                                               return false;
+
+                                       if (!TypeSpecComparer.Override.IsEqual (mi.ReturnType, base_method.ReturnType))
+                                               return false;
+                               }
+
+                               if (base_method != null) {
+                                       if (similar_candidate != null) {
+                                               Report.SymbolRelatedToPreviousError (similar_candidate);
+                                               Report.SymbolRelatedToPreviousError (mi);
+                                               Report.SymbolRelatedToPreviousError (container);
+                                               Report.Warning (1956, 1, ((MemberCore) base_method.MemberDefinition).Location,
+                                                       "The interface method `{0}' implementation is ambiguous between following methods: `{1}' and `{2}' in type `{3}'",
+                                                       mi.GetSignatureForError (), base_method.GetSignatureForError (), similar_candidate.GetSignatureForError (), container.GetSignatureForError ());
+                                       }
+
+                                       break;
+                               }
+
+                               base_type = candidates[0].DeclaringType.BaseType;
+                               if (base_type == null)
+                                       return false;
+                       }
+
+                       if (!base_method.IsVirtual) {
+#if STATIC
+                               var base_builder = base_method.GetMetaInfo () as MethodBuilder;
+                               if (base_builder != null) {
+                                       //
+                                       // We can avoid creating a proxy if base_method can be marked 'final virtual'. This can
+                                       // be done for all methods from compiled assembly
+                                       //
+                                       base_builder.__SetAttributes (base_builder.Attributes | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.NewSlot);
+                                       return true;
+                               }
+#endif
+                               DefineProxy (iface_type, base_method, mi);
+                       }
 
                        return true;
                }
@@ -558,57 +573,69 @@ namespace Mono.CSharp {
                        int i;
                        
                        for (i = 0; i < top; i++){
-                               Type type = pending_implementations [i].type;
-                               int j = 0;
+                               TypeSpec type = pending_implementations [i].type;
+
+                               bool base_implements_type = type.IsInterface &&
+                                       container.BaseType != null &&
+                                       container.BaseType.ImplementsInterface (type, false);
 
-                               foreach (MethodInfo mi in pending_implementations [i].methods){
+                               for (int j = 0; j < pending_implementations [i].methods.Count; ++j) {
+                                       var mi = pending_implementations[i].methods[j];
                                        if (mi == null)
                                                continue;
 
                                        if (type.IsInterface){
-                                               MethodInfo need_proxy =
+                                               var need_proxy =
                                                        pending_implementations [i].need_proxy [j];
 
                                                if (need_proxy != null) {
-                                                       Type [] args = TypeManager.GetParameterData (mi).Types;
-                                                       DefineProxy (type, need_proxy, mi, args);
+                                                       DefineProxy (type, need_proxy, mi);
                                                        continue;
                                                }
 
-                                               if (BaseImplements (type, mi))
-                                                       continue;
-                                               
                                                if (pending_implementations [i].optional)
                                                        continue;
 
+                                               MethodSpec candidate = null;
+                                               if (base_implements_type || BaseImplements (type, mi, out candidate))
+                                                       continue;
+
+                                               if (candidate == null) {
+                                                       MethodData md = pending_implementations [i].found [j];
+                                                       if (md != null)
+                                                               candidate = md.method.Spec;
+                                               }
+
                                                Report.SymbolRelatedToPreviousError (mi);
-                                               if (pending_implementations [i].found [j]) {
-                                                       if (mi.IsSpecialName) {
-                                                               string name = TypeManager.CSharpName (mi.DeclaringType) + '.' + mi.Name.Substring (4);
-                                                               Report.Error (551, container.Location, "Explicit interface implementation `{0}.{1}' is missing accessor `{2}'",
-                                                                       container.GetSignatureForError (), name, TypeManager.CSharpSignature (mi, true));
+                                               if (candidate != null) {
+                                                       Report.SymbolRelatedToPreviousError (candidate);
+                                                       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));
+                                                       } 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",
+                                                                       container.GetSignatureForError (), mi.GetSignatureForError (), candidate.GetSignatureForError ());
                                                        } else {
-                                                               string[] methodLabel = TypeManager.CSharpSignature (mi).Split ('.');
-                                                               Report.Error (536, container.Location,
-                                                                       "`{0}' does not implement interface member `{1}'. `{2}.{3}' " +
-                                                                       "is either static, not public, or has the wrong return type",
-                                                                       container.Name, TypeManager.CSharpSignature (mi),
-                                                                       container.Name, methodLabel[methodLabel.Length - 1]);
+                                                               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));
                                                        }
-                                               }
-                                               else {
+                                               } else {
                                                        Report.Error (535, container.Location, "`{0}' does not implement interface member `{1}'",
-                                                               container.GetSignatureForError (), TypeManager.CSharpSignature (mi));
+                                                               container.GetSignatureForError (), mi.GetSignatureForError ());
                                                }
                                        } else {
+                                               Report.SymbolRelatedToPreviousError (mi);
                                                Report.Error (534, container.Location, "`{0}' does not implement inherited abstract member `{1}'",
-                                                       container.GetSignatureForError (), TypeManager.CSharpSignature (mi, true));
+                                                       container.GetSignatureForError (), mi.GetSignatureForError ());
                                        }
                                        errors = true;
-                                       j++;
                                }
                        }
                        return errors;
                }
-       } /* end of class */
+       }
 }