X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fpending.cs;h=af15bf6e1c932ff3be8f3c3fd19f32a3f008bef0;hb=3f9310e59b924a8ef63dfef6c7f3c72935ac8f21;hp=23d80dfcc479c2ba3c39a1b70d1678394e18e22e;hpb=82e945bea3763efaa81d2d2222bedc0891fc66d0;p=mono.git diff --git a/mcs/mcs/pending.cs b/mcs/mcs/pending.cs index 23d80dfcc47..af15bf6e1c9 100644 --- a/mcs/mcs/pending.cs +++ b/mcs/mcs/pending.cs @@ -9,13 +9,20 @@ // // 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; + +#if STATIC +using IKVM.Reflection; +using IKVM.Reflection.Emit; +#else using System.Reflection; using System.Reflection.Emit; -using System.Linq; +#endif namespace Mono.CSharp { @@ -45,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 { /// /// The container for this PendingImplementation /// - TypeContainer container; + readonly TypeDefinition container; /// /// This is the array of TypeAndMethods that describes the pending implementations @@ -58,7 +137,7 @@ namespace Mono.CSharp { /// 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; @@ -91,6 +170,12 @@ namespace Mono.CSharp { } } + Report Report { + get { + return container.Module.Compiler.Report; + } + } + struct MissingInterfacesInfo { public TypeSpec Type; public bool Optional; @@ -102,22 +187,22 @@ namespace Mono.CSharp { } } - static MissingInterfacesInfo [] EmptyMissingInterfacesInfo = new MissingInterfacesInfo [0]; + 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 @@ -148,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; @@ -180,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 { @@ -194,14 +345,14 @@ namespace Mono.CSharp { /// /// Whether the specified method is an interface method implementation /// - 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); } /// @@ -221,21 +372,23 @@ namespace Mono.CSharp { /// that was used in the interface, then we always need to create a proxy for it. /// /// - 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]; @@ -270,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 @@ -283,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; } // @@ -294,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; } /// @@ -322,10 +487,11 @@ namespace Mono.CSharp { MethodBuilder proxy = container.TypeBuilder.DefineMethod ( proxy_name, + MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.CheckAccessOnOverride | - MethodAttributes.Virtual, + MethodAttributes.Virtual | MethodAttributes.Final, CallingConventions.Standard | CallingConventions.HasThis, base_method.ReturnType.GetMetaInfo (), param.GetMetaInfo ()); @@ -341,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); @@ -359,29 +526,131 @@ namespace Mono.CSharp { /// bool BaseImplements (TypeSpec iface_type, MethodSpec mi, out MethodSpec base_method) { + base_method = null; var base_type = container.BaseType; // // Setup filter with no return type to give better error message // about mismatch at return type when the check bellow rejects them // - var filter = new MemberFilter (mi.Name, mi.Arity, MemberKind.Method, mi.Parameters, null); + var parameters = mi.Parameters; + MethodSpec close_match = null; + + while (true) { + var candidates = MemberCache.FindMembers (base_type, mi.Name, false); + if (candidates == null) { + base_method = close_match; + return false; + } - base_method = (MethodSpec) MemberCache.FindMember (base_type, filter, BindingRestriction.None); + MethodSpec similar_candidate = null; + foreach (var candidate in candidates) { + if (candidate.Kind != MemberKind.Method) + continue; - if (base_method == null || (base_method.Modifiers & Modifiers.PUBLIC) == 0) - return false; + 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 (!TypeSpecComparer.Override.IsEqual (mi.ReturnType, base_method.ReturnType)) - 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; + + // + // 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; + } - 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) + 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 + // + var m = (MethodSpec) candidate; + + if (!m.IsPublic) { + if (close_match == null) + close_match = m; + + 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); + 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) { + base_method = close_match; + 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; } @@ -390,7 +659,7 @@ namespace Mono.CSharp { /// Verifies that any pending abstract methods or interface methods /// were implemented. /// - public bool VerifyPendingMethods (Report Report) + public bool VerifyPendingMethods () { int top = pending_implementations.Length; bool errors = false; @@ -436,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}'",