+ 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 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;
+ }
+
+ 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.IsEqual (parameters.Types, candidate_param.Types))
+ continue;
+
+ 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;
+ }
+
+ 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);
+ }