1de765fb4ac041eb7926c501e0aeb235c98579ad
[mono.git] / mcs / mcs / pending.cs
1 //
2 // pending.cs: Pending method implementation
3 //
4 // Authors:
5 //   Miguel de Icaza (miguel@gnu.org)
6 //   Marek Safar (marek.safar@gmail.com)
7 //
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 //
10 // Copyright 2001, 2002 Ximian, Inc (http://www.ximian.com)
11 // Copyright 2003-2008 Novell, Inc.
12 // Copyright 2011 Xamarin Inc
13 //
14
15 using System;
16 using System.Collections.Generic;
17 using System.Linq;
18
19 #if STATIC
20 using IKVM.Reflection;
21 using IKVM.Reflection.Emit;
22 #else
23 using System.Reflection;
24 using System.Reflection.Emit;
25 #endif
26
27 namespace Mono.CSharp {
28
29         struct TypeAndMethods {
30                 public TypeSpec          type;
31                 public IList<MethodSpec> methods;
32
33                 // 
34                 // Whether it is optional, this is used to allow the explicit/implicit
35                 // implementation when a base class already implements an interface. 
36                 //
37                 // For example:
38                 //
39                 // class X : IA { }  class Y : X, IA { IA.Explicit (); }
40                 //
41                 public bool          optional;
42                                 
43                 //
44                 // This flag on the method says `We found a match, but
45                 // because it was private, we could not use the match
46                 //
47                 public MethodData [] found;
48
49                 // If a method is defined here, then we always need to
50                 // create a proxy for it.  This is used when implementing
51                 // an interface's indexer with a different IndexerName.
52                 public MethodSpec [] need_proxy;
53         }
54
55         struct ProxyMethodContext : IMemberContext
56         {
57                 readonly TypeContainer container;
58
59                 public ProxyMethodContext (TypeContainer container)
60                 {
61                         this.container = container;
62                 }
63
64                 public TypeSpec CurrentType {
65                         get {
66                                 throw new NotImplementedException ();
67                         }
68                 }
69
70                 public TypeParameters CurrentTypeParameters {
71                         get {
72                                 throw new NotImplementedException ();
73                         }
74                 }
75
76                 public MemberCore CurrentMemberDefinition {
77                         get {
78                                 throw new NotImplementedException ();
79                         }
80                 }
81
82                 public bool IsObsolete {
83                         get {
84                                 return false;
85                         }
86                 }
87
88                 public bool IsUnsafe {
89                         get {
90                                 throw new NotImplementedException ();
91                         }
92                 }
93
94                 public bool IsStatic {
95                         get {
96                                 return false;
97                         }
98                 }
99
100                 public ModuleContainer Module {
101                         get {
102                                 return container.Module;
103                         }
104                 }
105
106                 public string GetSignatureForError ()
107                 {
108                         throw new NotImplementedException ();
109                 }
110
111                 public ExtensionMethodCandidates LookupExtensionMethod (string name, int arity)
112                 {
113                         throw new NotImplementedException ();
114                 }
115
116                 public FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
117                 {
118                         throw new NotImplementedException ();
119                 }
120
121                 public FullNamedExpression LookupNamespaceAlias (string name)
122                 {
123                         throw new NotImplementedException ();
124                 }
125         }
126
127         public class PendingImplementation
128         {
129                 /// <summary>
130                 ///   The container for this PendingImplementation
131                 /// </summary>
132                 readonly TypeDefinition container;
133                 
134                 /// <summary>
135                 ///   This is the array of TypeAndMethods that describes the pending implementations
136                 ///   (both interfaces and abstract methods in base class)
137                 /// </summary>
138                 TypeAndMethods [] pending_implementations;
139
140                 PendingImplementation (TypeDefinition container, MissingInterfacesInfo[] missing_ifaces, MethodSpec[] abstract_methods, int total)
141                 {
142                         var type_builder = container.Definition;
143                         
144                         this.container = container;
145                         pending_implementations = new TypeAndMethods [total];
146
147                         int i = 0;
148                         if (abstract_methods != null) {
149                                 int count = abstract_methods.Length;
150                                 pending_implementations [i].need_proxy = new MethodSpec [count];
151
152                                 pending_implementations [i].methods = abstract_methods;
153                                 pending_implementations [i].found = new MethodData [count];
154                                 pending_implementations [i].type = type_builder;
155                                 ++i;
156                         }
157
158                         foreach (MissingInterfacesInfo missing in missing_ifaces) {
159                                 var iface = missing.Type;
160                                 var mi = MemberCache.GetInterfaceMethods (iface);
161
162                                 int count = mi.Count;
163                                 pending_implementations [i].type = iface;
164                                 pending_implementations [i].optional = missing.Optional;
165                                 pending_implementations [i].methods = mi;
166                                 pending_implementations [i].found = new MethodData [count];
167                                 pending_implementations [i].need_proxy = new MethodSpec [count];
168                                 i++;
169                         }
170                 }
171
172                 Report Report {
173                         get {
174                                 return container.Module.Compiler.Report;
175                         }
176                 }
177
178                 struct MissingInterfacesInfo {
179                         public TypeSpec Type;
180                         public bool Optional;
181
182                         public MissingInterfacesInfo (TypeSpec t)
183                         {
184                                 Type = t;
185                                 Optional = false;
186                         }
187                 }
188
189                 static readonly MissingInterfacesInfo [] EmptyMissingInterfacesInfo = new MissingInterfacesInfo [0];
190                 
191                 static MissingInterfacesInfo [] GetMissingInterfaces (TypeDefinition container)
192                 {
193                         //
194                         // Interfaces will return all interfaces that the container
195                         // implements including any inherited interfaces
196                         //
197                         var impl = container.Definition.Interfaces;
198
199                         if (impl == null || impl.Count == 0)
200                                 return EmptyMissingInterfacesInfo;
201
202                         var ret = new MissingInterfacesInfo[impl.Count];
203
204                         for (int i = 0; i < ret.Length; i++)
205                                 ret [i] = new MissingInterfacesInfo (impl [i]);
206
207                         // we really should not get here because Object doesnt implement any
208                         // interfaces. But it could implement something internal, so we have
209                         // to handle that case.
210                         if (container.BaseType == null)
211                                 return ret;
212                         
213                         var base_impls = container.BaseType.Interfaces;
214                         if (base_impls != null) {
215                                 foreach (TypeSpec t in base_impls) {
216                                         for (int i = 0; i < ret.Length; i++) {
217                                                 if (t == ret[i].Type) {
218                                                         ret[i].Optional = true;
219                                                         break;
220                                                 }
221                                         }
222                                 }
223                         }
224
225                         return ret;
226                 }
227                 
228                 //
229                 // Factory method: if there are pending implementation methods, we return a PendingImplementation
230                 // object, otherwise we return null.
231                 //
232                 // Register method implementations are either abstract methods
233                 // flagged as such on the base class or interface methods
234                 //
235                 static public PendingImplementation GetPendingImplementations (TypeDefinition container)
236                 {
237                         TypeSpec b = container.BaseType;
238
239                         var missing_interfaces = GetMissingInterfaces (container);
240
241                         //
242                         // If we are implementing an abstract class, and we are not
243                         // ourselves abstract, and there are abstract methods (C# allows
244                         // abstract classes that have no abstract methods), then allocate
245                         // one slot.
246                         //
247                         // We also pre-compute the methods.
248                         //
249                         bool implementing_abstract = ((b != null) && b.IsAbstract && (container.ModFlags & Modifiers.ABSTRACT) == 0);
250                         MethodSpec[] abstract_methods = null;
251
252                         if (implementing_abstract){
253                                 var am = MemberCache.GetNotImplementedAbstractMethods (b);
254
255                                 if (am == null) {
256                                         implementing_abstract = false;
257                                 } else {
258                                         abstract_methods = new MethodSpec[am.Count];
259                                         am.CopyTo (abstract_methods, 0);
260                                 }
261                         }
262                         
263                         int total = missing_interfaces.Length +  (implementing_abstract ? 1 : 0);
264                         if (total == 0)
265                                 return null;
266
267                         var pending = new PendingImplementation (container, missing_interfaces, abstract_methods, total);
268
269                         //
270                         // check for inherited conflicting methods
271                         //
272                         foreach (var p in pending.pending_implementations) {
273                                 //
274                                 // It can happen for generic interfaces only
275                                 //
276                                 if (!p.type.IsGeneric)
277                                         continue;
278
279                                 //
280                                 // CLR does not distinguishes between ref and out
281                                 //
282                                 for (int i = 0; i < p.methods.Count; ++i) {
283                                         MethodSpec compared_method = p.methods[i];
284                                         if (compared_method.Parameters.IsEmpty)
285                                                 continue;
286
287                                         for (int ii = i + 1; ii < p.methods.Count; ++ii) {
288                                                 MethodSpec tested_method = p.methods[ii];
289                                                 if (compared_method.Name != tested_method.Name)
290                                                         continue;
291
292                                                 if (p.type != tested_method.DeclaringType)
293                                                         continue;
294
295                                                 if (!TypeSpecComparer.Override.IsSame (compared_method.Parameters.Types, tested_method.Parameters.Types))
296                                                         continue;
297
298                                                 bool exact_match = true;
299                                                 bool ref_only_difference = false;
300                                                 var cp = compared_method.Parameters.FixedParameters;
301                                                 var tp = tested_method.Parameters.FixedParameters;
302
303                                                 for (int pi = 0; pi < cp.Length; ++pi) {
304                                                         //
305                                                         // First check exact modifiers match
306                                                         //
307                                                         if ((cp[pi].ModFlags & Parameter.Modifier.RefOutMask) == (tp[pi].ModFlags & Parameter.Modifier.RefOutMask))
308                                                                 continue;
309
310                                                         if (((cp[pi].ModFlags | tp[pi].ModFlags) & Parameter.Modifier.RefOutMask) == Parameter.Modifier.RefOutMask) {
311                                                                 ref_only_difference = true;
312                                                                 continue;
313                                                         }
314
315                                                         exact_match = false;
316                                                         break;
317                                                 }
318
319                                                 if (!exact_match || !ref_only_difference)
320                                                         continue;
321
322                                                 pending.Report.SymbolRelatedToPreviousError (compared_method);
323                                                 pending.Report.SymbolRelatedToPreviousError (tested_method);
324                                                 pending.Report.Error (767, container.Location,
325                                                         "Cannot implement interface `{0}' with the specified type parameters because it causes method `{1}' to differ on parameter modifiers only",
326                                                         p.type.GetDefinition().GetSignatureForError (), compared_method.GetSignatureForError ());
327
328                                                 break;
329                                         }
330                                 }
331                         }
332
333                         return pending;
334                 }
335
336                 public enum Operation {
337                         //
338                         // If you change this, review the whole InterfaceMethod routine as there
339                         // are a couple of assumptions on these three states
340                         //
341                         Lookup, ClearOne, ClearAll
342                 }
343
344                 /// <summary>
345                 ///   Whether the specified method is an interface method implementation
346                 /// </summary>
347                 public MethodSpec IsInterfaceMethod (MemberName name, TypeSpec ifaceType, MethodData method, out MethodSpec ambiguousCandidate, ref bool optional)
348                 {
349                         return InterfaceMethod (name, ifaceType, method, Operation.Lookup, out ambiguousCandidate, ref optional);
350                 }
351
352                 public void ImplementMethod (MemberName name, TypeSpec ifaceType, MethodData method, bool clear_one, out MethodSpec ambiguousCandidate, ref bool optional)
353                 {
354                         InterfaceMethod (name, ifaceType, method, clear_one ? Operation.ClearOne : Operation.ClearAll, out ambiguousCandidate, ref optional);
355                 }
356
357                 /// <remarks>
358                 ///   If a method in Type `t' (or null to look in all interfaces
359                 ///   and the base abstract class) with name `Name', return type `ret_type' and
360                 ///   arguments `args' implements an interface, this method will
361                 ///   return the MethodInfo that this method implements.
362                 ///
363                 ///   If `name' is null, we operate solely on the method's signature.  This is for
364                 ///   instance used when implementing indexers.
365                 ///
366                 ///   The `Operation op' controls whether to lookup, clear the pending bit, or clear
367                 ///   all the methods with the given signature.
368                 ///
369                 ///   The `MethodInfo need_proxy' is used when we're implementing an interface's
370                 ///   indexer in a class.  If the new indexer's IndexerName does not match the one
371                 ///   that was used in the interface, then we always need to create a proxy for it.
372                 ///
373                 /// </remarks>
374                 public MethodSpec InterfaceMethod (MemberName name, TypeSpec iType, MethodData method, Operation op, out MethodSpec ambiguousCandidate, ref bool optional)
375                 {
376                         ambiguousCandidate = null;
377
378                         if (pending_implementations == null)
379                                 return null;
380
381                         TypeSpec ret_type = method.method.ReturnType;
382                         ParametersCompiled args = method.method.ParameterInfo;
383                         bool is_indexer = method.method is Indexer.SetIndexerMethod || method.method is Indexer.GetIndexerMethod;
384                         MethodSpec m;
385
386                         foreach (TypeAndMethods tm in pending_implementations){
387                                 if (!(iType == null || tm.type == iType))
388                                         continue;
389
390                                 int method_count = tm.methods.Count;
391                                 for (int i = 0; i < method_count; i++){
392                                         m = tm.methods [i];
393
394                                         if (m == null)
395                                                 continue;
396
397                                         if (is_indexer) {
398                                                 if (!m.IsAccessor || m.Parameters.IsEmpty)
399                                                         continue;
400                                         } else {
401                                                 if (name.Name != m.Name)
402                                                         continue;
403
404                                                 if (m.Arity != name.Arity)
405                                                         continue;
406                                         }
407
408                                         if (!TypeSpecComparer.Override.IsEqual (m.Parameters, args))
409                                                 continue;
410
411                                         if (!TypeSpecComparer.Override.IsEqual (m.ReturnType, ret_type)) {
412                                                 tm.found[i] = method;
413                                                 continue;
414                                         }
415
416                                         //
417                                         // `need_proxy' is not null when we're implementing an
418                                         // interface indexer and this is Clear(One/All) operation.
419                                         //
420                                         // If `name' is null, then we do a match solely based on the
421                                         // signature and not on the name (this is done in the Lookup
422                                         // for an interface indexer).
423                                         //
424                                         if (op != Operation.Lookup) {
425                                                 if (m.IsAccessor != method.method.IsAccessor)
426                                                         continue;
427
428                                                 // If `t != null', then this is an explicitly interface
429                                                 // implementation and we can always clear the method.
430                                                 // `need_proxy' is not null if we're implementing an
431                                                 // interface indexer.  In this case, we need to create
432                                                 // a proxy if the implementation's IndexerName doesn't
433                                                 // match the IndexerName in the interface.
434                                                 if (m.DeclaringType.IsInterface && iType == null && name.Name != m.Name) {      // TODO: This is very expensive comparison
435                                                         tm.need_proxy[i] = method.method.Spec;
436                                                 } else {
437                                                         tm.methods[i] = null;
438                                                 }
439                                         } else {
440                                                 tm.found [i] = method;
441                                                 optional = tm.optional;
442                                         }
443
444                                         if (op == Operation.Lookup && name.ExplicitInterface != null && ambiguousCandidate == null) {
445                                                 ambiguousCandidate = m;
446                                                 continue;
447                                         }
448
449                                         //
450                                         // Lookups and ClearOne return
451                                         //
452                                         if (op != Operation.ClearAll)
453                                                 return m;
454                                 }
455
456                                 // If a specific type was requested, we can stop now.
457                                 if (tm.type == iType)
458                                         break;
459                         }
460
461                         m = ambiguousCandidate;
462                         ambiguousCandidate = null;
463                         return m;
464                 }
465
466                 /// <summary>
467                 ///   C# allows this kind of scenarios:
468                 ///   interface I { void M (); }
469                 ///   class X { public void M (); }
470                 ///   class Y : X, I { }
471                 ///
472                 ///   For that case, we create an explicit implementation function
473                 ///   I.M in Y.
474                 /// </summary>
475                 void DefineProxy (TypeSpec iface, MethodSpec base_method, MethodSpec iface_method)
476                 {
477                         // TODO: Handle nested iface names
478                         string proxy_name;
479                         var ns = iface.MemberDefinition.Namespace;
480                         if (string.IsNullOrEmpty (ns))
481                                 proxy_name = iface.MemberDefinition.Name + "." + iface_method.Name;
482                         else
483                                 proxy_name = ns + "." + iface.MemberDefinition.Name + "." + iface_method.Name;
484
485                         var param = iface_method.Parameters;
486
487                         MethodBuilder proxy = container.TypeBuilder.DefineMethod (
488                                 proxy_name,
489                                 MethodAttributes.Private |
490                                 MethodAttributes.HideBySig |
491                                 MethodAttributes.NewSlot |
492                                 MethodAttributes.CheckAccessOnOverride |
493                                 MethodAttributes.Virtual | MethodAttributes.Final,
494                                 CallingConventions.Standard | CallingConventions.HasThis,
495                                 base_method.ReturnType.GetMetaInfo (), param.GetMetaInfo ());
496
497                         if (iface_method.IsGeneric) {
498                                 var gnames = iface_method.GenericDefinition.TypeParameters.Select (l => l.Name).ToArray ();
499                                 proxy.DefineGenericParameters (gnames);
500                         }
501
502                         for (int i = 0; i < param.Count; i++) {
503                                 string name = param.FixedParameters [i].Name;
504                                 ParameterAttributes attr = ParametersCompiled.GetParameterAttribute (param.FixedParameters [i].ModFlags);
505                                 proxy.DefineParameter (i + 1, attr, name);
506                         }
507
508                         int top = param.Count;
509                         var ec = new EmitContext (new ProxyMethodContext (container), proxy.GetILGenerator (), null, null);
510                         ec.EmitThis ();
511                         // TODO: GetAllParametersArguments
512                         for (int i = 0; i < top; i++)
513                                 ec.EmitArgumentLoad (i);
514
515                         ec.Emit (OpCodes.Call, base_method);
516                         ec.Emit (OpCodes.Ret);
517
518                         container.TypeBuilder.DefineMethodOverride (proxy, (MethodInfo) iface_method.GetMetaInfo ());
519                 }
520                 
521                 /// <summary>
522                 ///   This function tells whether one of our base classes implements
523                 ///   the given method (which turns out, it is valid to have an interface
524                 ///   implementation in a base
525                 /// </summary>
526                 bool BaseImplements (TypeSpec iface_type, MethodSpec mi, out MethodSpec base_method)
527                 {
528                         base_method = null;
529                         bool base_can_implement = true;
530                         TypeSpec lookup_type;
531
532                         //
533                         // Special handling for properties/indexers which cannot have accessors
534                         // implementing an interface found in different types (e.g. current and base)
535                         //
536                         if (mi.IsAccessor && container.Interfaces != null) {
537
538                                 bool new_implementation = false;
539                                 foreach (var iface in container.Interfaces) {
540                                         if (TypeSpecComparer.IsEqual (iface, iface_type)) {
541                                                 new_implementation = true;
542                                                 break;
543                                         }
544                                 }
545
546                                 if (new_implementation) {
547                                         MemberFilter filter;
548                                         bool getter = mi.Name [0] == 'g';
549                                         if (mi.Parameters.Count > (getter ? 0 : 1)) {
550                                                 var indexer_params = getter ? mi.Parameters : IndexerSpec.CreateParametersFromSetter (mi, mi.Parameters.Count - 1);
551                                                 var ptype = getter ? mi.ReturnType : mi.Parameters.Types [mi.Parameters.Count - 1];
552                                                 filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, indexer_params, ptype);
553                                         } else {
554                                                 var pname = mi.Name.Substring (4);
555                                                 var ptype = getter ? mi.ReturnType : mi.Parameters.Types [0];
556                                                 filter = MemberFilter.Property (pname, ptype);
557                                         }
558
559                                         var prop = MemberCache.FindMember (container.CurrentType, filter, BindingRestriction.DeclaredOnly | BindingRestriction.InstanceOnly);
560                                         if (prop != null && (prop.Modifiers & Modifiers.NEW) != 0)
561                                                 base_can_implement = false;
562                                 }
563                         }
564
565                         if (base_can_implement) {
566                                 lookup_type = container.BaseType;
567
568                                 if (lookup_type.ImplementsInterface (iface_type, false))
569                                         return true;
570                         } else {
571                                 lookup_type = container.CurrentType;
572                         }
573
574                         //
575                         // Setup filter with no return type to give better error message
576                         // about mismatch at return type when the check bellow rejects them
577                         //
578                         var parameters = mi.Parameters;
579                         MethodSpec close_match = null;
580
581                         while (true) {
582                                 var candidates = MemberCache.FindMembers (lookup_type, mi.Name, !base_can_implement);
583                                 if (candidates == null) {
584                                         base_method = close_match;
585                                         return false;
586                                 }
587
588                                 MethodSpec similar_candidate = null;
589                                 foreach (var candidate in candidates) {
590                                         if (candidate.Kind != MemberKind.Method)
591                                                 continue;
592
593                                         if (candidate.Arity != mi.Arity)
594                                                 continue;
595
596                                         var candidate_param = ((MethodSpec) candidate).Parameters;
597                                         if (!TypeSpecComparer.Override.IsEqual (parameters.Types, candidate_param.Types))
598                                                 continue;
599
600                                         bool modifiers_match = true;
601                                         for (int i = 0; i < parameters.Count; ++i) {
602                                                 //
603                                                 // First check exact ref/out match
604                                                 //
605                                                 if ((parameters.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) == (candidate_param.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
606                                                         continue;
607
608                                                 modifiers_match = false;
609
610                                                 //
611                                                 // Different in ref/out only
612                                                 //
613                                                 if ((parameters.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (candidate_param.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask)) {
614                                                         if (similar_candidate == null) {
615                                                                 if (!candidate.IsPublic)
616                                                                         break;
617
618                                                                 if (!TypeSpecComparer.Override.IsEqual (mi.ReturnType, ((MethodSpec) candidate).ReturnType))
619                                                                         break;
620
621                                                                 // It's used for ref/out ambiguity overload check
622                                                                 similar_candidate = (MethodSpec) candidate;
623                                                         }
624
625                                                         continue;
626                                                 }
627
628                                                 similar_candidate = null;
629                                                 break;
630                                         }
631
632                                         if (!modifiers_match)
633                                                 continue;
634
635                                         //
636                                         // From this point the candidate is used for detailed error reporting
637                                         // because it's very close match to what we are looking for
638                                         //
639                                         var m = (MethodSpec) candidate;
640
641                                         if (!m.IsPublic) {
642                                                 if (close_match == null)
643                                                         close_match = m;
644
645                                                 continue;
646                                         }
647
648                                         if (!TypeSpecComparer.Override.IsEqual (mi.ReturnType, m.ReturnType)) {
649                                                 if (close_match == null)
650                                                         close_match = m;
651
652                                                 continue;
653                                         }
654                                                 
655                                         base_method = m;
656
657                                         if (mi.IsGeneric && !Method.CheckImplementingMethodConstraints (container, m, mi)) {
658                                                 return true;
659                                         }
660                                 }
661                                 
662                                 if (base_method != null) {
663                                         if (similar_candidate != null) {
664                                                 Report.SymbolRelatedToPreviousError (similar_candidate);
665                                                 Report.SymbolRelatedToPreviousError (mi);
666                                                 Report.SymbolRelatedToPreviousError (container);
667                                                 Report.Warning (1956, 1, ((MemberCore) base_method.MemberDefinition).Location,
668                                                         "The interface method `{0}' implementation is ambiguous between following methods: `{1}' and `{2}' in type `{3}'",
669                                                         mi.GetSignatureForError (), base_method.GetSignatureForError (), similar_candidate.GetSignatureForError (), container.GetSignatureForError ());
670                                         }
671
672                                         break;
673                                 }
674
675                                 if (!base_can_implement)
676                                         return false;
677
678                                 lookup_type = candidates[0].DeclaringType.BaseType;
679                                 if (lookup_type == null) {
680                                         base_method = close_match;
681                                         return false;
682                                 }
683                         }
684
685                         if (!base_method.IsVirtual) {
686 #if STATIC
687                                 var base_builder = base_method.GetMetaInfo () as MethodBuilder;
688                                 if (base_builder != null) {
689                                         //
690                                         // We can avoid creating a proxy if base_method can be marked 'final virtual'. This can
691                                         // be done for all methods from compiled assembly
692                                         //
693                                         base_builder.__SetAttributes (base_builder.Attributes | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.NewSlot);
694                                         return true;
695                                 }
696 #endif
697                                 DefineProxy (iface_type, base_method, mi);
698                         }
699
700                         return true;
701                 }
702
703                 /// <summary>
704                 ///   Verifies that any pending abstract methods or interface methods
705                 ///   were implemented.
706                 /// </summary>
707                 public bool VerifyPendingMethods ()
708                 {
709                         int top = pending_implementations.Length;
710                         bool errors = false;
711                         int i;
712                         
713                         for (i = 0; i < top; i++){
714                                 TypeSpec type = pending_implementations [i].type;
715
716                                 for (int j = 0; j < pending_implementations [i].methods.Count; ++j) {
717                                         var mi = pending_implementations[i].methods[j];
718                                         if (mi == null)
719                                                 continue;
720
721                                         if (type.IsInterface){
722                                                 var need_proxy =
723                                                         pending_implementations [i].need_proxy [j];
724
725                                                 if (need_proxy != null) {
726                                                         DefineProxy (type, need_proxy, mi);
727                                                         continue;
728                                                 }
729
730                                                 MethodSpec candidate;
731                                                 if (BaseImplements (type, mi, out candidate))
732                                                         continue;
733
734                                                 if (candidate == null) {
735                                                         MethodData md = pending_implementations [i].found [j];
736                                                         if (md != null)
737                                                                 candidate = md.method.Spec;
738                                                 }
739
740                                                 Report.SymbolRelatedToPreviousError (mi);
741                                                 if (candidate != null) {
742                                                         Report.SymbolRelatedToPreviousError (candidate);
743                                                         if (candidate.IsStatic) {
744                                                                 Report.Error (736, container.Location,
745                                                                         "`{0}' does not implement interface member `{1}' and the best implementing candidate `{2}' is static",
746                                                                         container.GetSignatureForError (), mi.GetSignatureForError (), candidate.GetSignatureForError ());
747                                                         } else if ((candidate.Modifiers & Modifiers.PUBLIC) == 0) {
748                                                                 Report.Error (737, container.Location,
749                                                                         "`{0}' does not implement interface member `{1}' and the best implementing candidate `{2}' is not public",
750                                                                         container.GetSignatureForError (), mi.GetSignatureForError (), candidate.GetSignatureForError ());
751                                                         } else {
752                                                                 Report.Error (738, container.Location,
753                                                                         "`{0}' does not implement interface member `{1}' and the best implementing candidate `{2}' return type `{3}' does not match interface member return type `{4}'",
754                                                                         container.GetSignatureForError (), mi.GetSignatureForError (), candidate.GetSignatureForError (),
755                                                                         candidate.ReturnType.GetSignatureForError (), mi.ReturnType.GetSignatureForError ());
756                                                         }
757                                                 } else {
758                                                         Report.Error (535, container.Location, "`{0}' does not implement interface member `{1}'",
759                                                                 container.GetSignatureForError (), mi.GetSignatureForError ());
760                                                 }
761                                         } else {
762                                                 Report.SymbolRelatedToPreviousError (mi);
763                                                 Report.Error (534, container.Location, "`{0}' does not implement inherited abstract member `{1}'",
764                                                         container.GetSignatureForError (), mi.GetSignatureForError ());
765                                         }
766                                         errors = true;
767                                 }
768                         }
769                         return errors;
770                 }
771         }
772 }