X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fpending.cs;h=7684c117c04c0c346ed7b96f59d261dbcc1a572b;hb=f3edca943070399b06d33f3ba3e99c76a9d9886d;hp=9cc30e213d862be9a8ab111b99a06dea14b0f36f;hpb=a5e40870bd3bb18e1681afed6c71e7edfdb80534;p=mono.git diff --git a/mcs/mcs/pending.cs b/mcs/mcs/pending.cs index 9cc30e213d8..7684c117c04 100644 --- a/mcs/mcs/pending.cs +++ b/mcs/mcs/pending.cs @@ -1,25 +1,34 @@ // // pending.cs: Pending method implementation // -// Author: +// Authors: // Miguel de Icaza (miguel@gnu.org) +// Marek Safar (marek.safar@gmail.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. +// Copyright 2011 Xamarin 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 methods; // // Whether it is optional, this is used to allow the explicit/implicit @@ -30,14 +39,7 @@ 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 @@ -47,231 +49,180 @@ namespace Mono.CSharp { // 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; + public MethodSpec [] need_proxy; } - public class PendingImplementation { - /// - /// The container for this PendingImplementation - /// - TypeContainer container; - - /// - /// This filter is used by FindMembers, and it is used to - /// extract only virtual/abstract fields - /// - static MemberFilter virtual_method_filter; - - /// - /// This is the array of TypeAndMethods that describes the pending implementations - /// (both interfaces and abstract methods in base class) - /// - TypeAndMethods [] pending_implementations; + struct ProxyMethodContext : IMemberContext + { + readonly TypeContainer container; - static bool IsVirtualFilter (MemberInfo m, object filterCriteria) + public ProxyMethodContext (TypeContainer container) { - MethodInfo mi = m as MethodInfo; - return (mi == null) ? false : mi.IsVirtual; + this.container = container; } - /// - /// Inits the virtual_method_filter - /// - static PendingImplementation () - { - virtual_method_filter = new MemberFilter (IsVirtualFilter); + public TypeSpec CurrentType { + get { + throw new NotImplementedException (); + } } - // - // 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. - // - 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; - } + public TypeParameters CurrentTypeParameters { + get { + throw new NotImplementedException (); + } + } - if (mi.Count == 0) - continue; + public MemberCore CurrentMemberDefinition { + get { + throw new NotImplementedException (); + } + } - if (mi.Count == 1 && !(mi [0] is MethodBase)) - searching = false; - else - list = TypeManager.CopyNewMethods (list, mi); - } while (searching); + public bool IsObsolete { + get { + return false; + } + } - if (list == null) - return null; - - for (int i = 0; i < list.Count; i++){ - while (list.Count > i && !((MethodInfo) list [i]).IsAbstract) - list.RemoveAt (i); + public bool IsUnsafe { + get { + throw new NotImplementedException (); } + } - if (list.Count == 0) - return null; + 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 (); + } - return list; + public FullNamedExpression LookupNamespaceAlias (string name) + { + throw new NotImplementedException (); } + } + + public class PendingImplementation + { + /// + /// The container for this PendingImplementation + /// + readonly TypeDefinition container; + + /// + /// This is the array of TypeAndMethods that describes the pending implementations + /// (both interfaces and abstract methods in base class) + /// + TypeAndMethods [] pending_implementations; - PendingImplementation (TypeContainer container, MissingInterfacesInfo [] missing_ifaces, ArrayList abstract_methods, int total) + PendingImplementation (TypeDefinition container, MissingInterfacesInfo[] missing_ifaces, MethodSpec[] 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; 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); + int count = abstract_methods.Length; + pending_implementations [i].methods = new MethodSpec [count]; + pending_implementations [i].need_proxy = new MethodSpec [count]; + + pending_implementations [i].methods = abstract_methods; pending_implementations [i].found = new MethodData [count]; - pending_implementations [i].args = new Type [count][]; - pending_implementations [i].mods = new Parameter.Modifier [count][]; pending_implementations [i].type = type_builder; - - int j = 0; - foreach (MemberInfo m in abstract_methods) { - MethodInfo mi = (MethodInfo) m; - - AParametersCollection 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.FixedParameters[k].ModFlags; - pending_implementations [i].mods [j] = pm; - } - - j++; - } ++i; } foreach (MissingInterfacesInfo missing in missing_ifaces) { - MethodInfo [] mi; - Type t = missing.Type; - - if (!t.IsInterface) - continue; + var iface = missing.Type; + var mi = MemberCache.GetInterfaceMethods (iface); - if (t is TypeBuilder){ - TypeContainer iface; - - iface = TypeManager.LookupInterface (t); - - mi = iface.GetMethods (); - } else - mi = t.GetMethods (); - - 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 MethodData [count]; - pending_implementations [i].need_proxy = new MethodInfo [count]; - - int j = 0; - foreach (MethodInfo m in mi){ - pending_implementations [i].args [j] = Type.EmptyTypes; - pending_implementations [i].mods [j] = null; - - // If there is a previous error, just ignore - if (m == null) - continue; - - AParametersCollection 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.FixedParameters [k].ModFlags; - pending_implementations [i].mods [j] = pm; - } - - j++; - } + pending_implementations [i].need_proxy = new MethodSpec [count]; i++; } } + 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 (TypeDefinition 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; } @@ -282,13 +233,11 @@ 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) { - 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 @@ -298,21 +247,91 @@ 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 + // + 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 { @@ -326,14 +345,14 @@ namespace Mono.CSharp { /// /// Whether the specified method is an interface method implementation /// - public MethodInfo IsInterfaceMethod (string name, Type 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 (string name, Type 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); } /// @@ -353,38 +372,47 @@ namespace Mono.CSharp { /// that was used in the interface, then we always need to create a proxy for it. /// /// - public MethodInfo InterfaceMethod (string name, Type 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; - Type ret_type = method.method.ReturnType; - Parameters args = method.method.ParameterInfo; - int arg_len = args.Count; + 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.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; - // - // Check if we have the same parameters - // + if (is_indexer) { + if (!m.IsAccessor || m.Parameters.IsEmpty) + continue; + } else { + if (name.Name != m.Name) + continue; - if (tm.args [i] == null && arg_len != 0) - continue; - if (tm.args [i] != null && tm.args [i].Length != arg_len) + if (m.Arity != name.Arity) + continue; + } + + if (!TypeSpecComparer.Override.IsEqual (m.Parameters, args)) continue; - string mname = TypeManager.GetMethodName (m); + if (!TypeSpecComparer.Override.IsEqual (m.ReturnType, ret_type)) { + tm.found[i] = method; + continue; + } // // `need_proxy' is not null when we're implementing an @@ -394,57 +422,30 @@ namespace Mono.CSharp { // signature and not on the name (this is done in the Lookup // for an interface indexer). // - - if (is_indexer) { - IMethodData md = TypeManager.GetMethod (m); - if (md != null) { - if (!(md is Indexer.SetIndexerMethod || md is Indexer.GetIndexerMethod)) - continue; - } else { - if (TypeManager.GetPropertyFromAccessor (m) == null) - continue; - } - } else if (name != mname) { - continue; - } - - int j; - - for (j = 0; j < arg_len; j++) { - if (!TypeManager.IsEqual (tm.args [i][j], args.Types [j])) - break; - if (tm.mods [i][j] == args.FixedParameters [j].ModFlags) + if (op != Operation.Lookup) { + if (m.IsAccessor != method.method.IsAccessor) 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.FixedParameters [j].ModFlags != 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. - if (iType == null && name != mname) - tm.need_proxy [i] = method.MethodBuilder; - 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; + optional = tm.optional; } - Type rt = TypeManager.TypeToCoreType (m.ReturnType); - if (!TypeManager.IsEqual (ret_type, rt) && - !(ret_type == null && rt == TypeManager.void_type) && - !(rt == null && ret_type == TypeManager.void_type)) + if (op == Operation.Lookup && name.ExplicitInterface != null && ambiguousCandidate == null) { + ambiguousCandidate = m; continue; + } // // Lookups and ClearOne return @@ -455,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; } /// @@ -469,39 +473,50 @@ namespace Mono.CSharp { /// For that case, we create an explicit implementation function /// I.M in Y. /// - void DefineProxy (Type iface, MethodInfo base_method, MethodInfo iface_method, - AParametersCollection param) + 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 = SimpleName.RemoveGenericArity (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, param.GetEmitTypes ()); + base_method.ReturnType.GetMetaInfo (), param.GetMetaInfo ()); + + if (iface_method.IsGeneric) { + var gnames = iface_method.GenericDefinition.TypeParameters.Select (l => l.Name).ToArray (); + proxy.DefineGenericParameters (gnames); + } - AParametersCollection pd = TypeManager.GetParameterData (iface_method); - proxy.DefineParameter (0, ParameterAttributes.None, ""); - for (int i = 0; i < pd.Count; i++) { - string name = pd.FixedParameters [i].Name; - ParameterAttributes attr = Parameters.GetParameterAttribute (pd.FixedParameters [i].ModFlags); + 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; - ILGenerator ig = proxy.GetILGenerator (); - - for (int i = 0; i <= top; i++) - ParameterReference.EmitLdArg (ig, i); + var ec = new EmitContext (new ProxyMethodContext (container), proxy.GetILGenerator (), null, null); + ec.EmitThis (); + // TODO: GetAllParametersArguments + for (int i = 0; i < top; i++) + ec.EmitArgumentLoad (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 ()); } /// @@ -509,39 +524,117 @@ namespace Mono.CSharp { /// the given method (which turns out, it is valid to have an interface /// implementation in a base /// - bool BaseImplements (Type iface_type, MethodInfo mi, out MethodInfo base_method) + bool BaseImplements (TypeSpec iface_type, MethodSpec mi, out MethodSpec base_method) { - MethodSignature ms; - - AParametersCollection param = TypeManager.GetParameterData (mi); - ms = new MethodSignature (mi.Name, TypeManager.TypeToCoreType (mi.ReturnType), param.Types); - MemberList list = TypeContainer.FindMembers ( - container.TypeBuilder.BaseType, MemberTypes.Method | MemberTypes.Property, - BindingFlags.Public | BindingFlags.Instance, - MethodSignature.method_signature_filter, ms); - - if (list.Count == 0) { - base_method = null; - return false; - } + base_method = null; + var base_type = container.BaseType; - if (TypeManager.ImplementsInterface (container.TypeBuilder.BaseType, iface_type)) { - base_method = null; - return true; - } + // + // Setup filter with no return type to give better error message + // about mismatch at return type when the check bellow rejects them + // + 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; - base_method = (MethodInfo) list [0]; + if (candidate.Arity != mi.Arity) + continue; - if (base_method.DeclaringType.IsInterface) - return false; + var candidate_param = ((MethodSpec) candidate).Parameters; + if (!TypeSpecComparer.Override.IsEqual (parameters.Types, candidate_param.Types)) + continue; - if (!base_method.IsPublic) - return false; + bool modifiers_match = true; + for (int i = 0; i < parameters.Count; ++i) { + // + // First check exact ref/out match + // + if ((parameters.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) == (candidate_param.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask)) + continue; + + modifiers_match = false; - if (!base_method.IsAbstract && !base_method.IsVirtual) - // FIXME: We can avoid creating a proxy if base_method can be marked 'final virtual' instead. - // However, it's too late now, the MethodBuilder has already been created (see bug 377519) - DefineProxy (iface_type, base_method, mi, param); + // + // Different in ref/out only + // + if ((parameters.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (candidate_param.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask)) { + 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 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 (!candidate.IsPublic) + return false; + + if (!TypeSpecComparer.Override.IsEqual (mi.ReturnType, base_method.ReturnType)) + return false; + + if (mi.IsGeneric && !Method.CheckImplementingMethodConstraints (container, base_method, mi)) { + return true; + } + } + + 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; } @@ -557,69 +650,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.TypeBuilder.BaseType != null && - TypeManager.ImplementsInterface (container.TypeBuilder.BaseType, type); + 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) { - DefineProxy (type, need_proxy, mi, TypeManager.GetParameterData (mi)); + DefineProxy (type, need_proxy, mi); continue; } if (pending_implementations [i].optional) continue; - MethodInfo candidate = null; + 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.MethodBuilder; + candidate = md.method.Spec; } - + Report.SymbolRelatedToPreviousError (mi); 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 (), TypeManager.CSharpSignature (mi, true), TypeManager.CSharpSignature (candidate)); - } else if (!candidate.IsPublic) { + 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", - container.GetSignatureForError (), TypeManager.CSharpSignature (mi, true), TypeManager.CSharpSignature (candidate, true)); + "`{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 (), TypeManager.CSharpSignature (mi, true), 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}'", - container.GetSignatureForError (), TypeManager.CSharpSignature (mi, true)); + 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 */ + } }