Revert 73805, 73806, 73807
[mono.git] / mcs / mcs / pending.cs
1 //
2 // pending.cs: Pending method implementation
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@gnu.org)
6 //
7 // Licensed under the terms of the GNU GPL
8 //
9 // (C) 2001, 2002 Ximian, Inc (http://www.ximian.com)
10 //
11 //
12
13 using System;
14 using System.Collections;
15 using System.Reflection;
16 using System.Reflection.Emit;
17
18 namespace Mono.CSharp {
19
20         struct TypeAndMethods {
21                 public Type          type;
22                 public MethodInfo [] methods;
23
24                 // 
25                 // Whether it is optional, this is used to allow the explicit/implicit
26                 // implementation when a base class already implements an interface. 
27                 //
28                 // For example:
29                 //
30                 // class X : IA { }  class Y : X, IA { IA.Explicit (); }
31                 //
32                 public bool          optional;
33                 
34                 // Far from ideal, but we want to avoid creating a copy
35                 // of methods above.
36                 public Type [][]     args;
37
38                 //This is used to store the modifiers of arguments
39                 public Parameter.Modifier [][] mods;
40                 
41                 //
42                 // This flag on the method says `We found a match, but
43                 // because it was private, we could not use the match
44                 //
45                 public bool []       found;
46
47                 // If a method is defined here, then we always need to
48                 // create a proxy for it.  This is used when implementing
49                 // an interface's indexer with a different IndexerName.
50                 public MethodInfo [] need_proxy;
51
52                 //
53                 // The name of the indexer (if it exists), precompute set/get, because
54                 // they would be recomputed many times inside a loop later on.
55                 //
56                 public string set_indexer_name;
57                 public string get_indexer_name;
58         }
59
60         public class PendingImplementation {
61                 /// <summary>
62                 ///   The container for this PendingImplementation
63                 /// </summary>
64                 TypeContainer container;
65                 
66                 /// <summary>
67                 ///   This filter is used by FindMembers, and it is used to
68                 ///   extract only virtual/abstract fields
69                 /// </summary>
70                 static MemberFilter virtual_method_filter;
71
72                 /// <summary>
73                 ///   This is the array of TypeAndMethods that describes the pending implementations
74                 ///   (both interfaces and abstract methods in base class)
75                 /// </summary>
76                 TypeAndMethods [] pending_implementations;
77
78                 static bool IsVirtualFilter (MemberInfo m, object filterCriteria)
79                 {
80                         MethodInfo mi = m as MethodInfo;
81                         return (mi == null) ? false : mi.IsVirtual;
82                 }
83
84                 /// <summary>
85                 ///   Inits the virtual_method_filter
86                 /// </summary>
87                 static PendingImplementation ()
88                 {
89                         virtual_method_filter = new MemberFilter (IsVirtualFilter);
90                 }
91
92                 // <remarks>
93                 //   Returns a list of the abstract methods that are exposed by all of our
94                 //   bases that we must implement.  Notice that this `flattens' the
95                 //   method search space, and takes into account overrides.  
96                 // </remarks>
97                 static ArrayList GetAbstractMethods (Type t)
98                 {
99                         ArrayList list = null;
100                         bool searching = true;
101                         Type current_type = t;
102                         
103                         do {
104                                 MemberList mi;
105                                 
106                                 mi = TypeContainer.FindMembers (
107                                         current_type, MemberTypes.Method,
108                                         BindingFlags.Public | BindingFlags.NonPublic |
109                                         BindingFlags.Instance | BindingFlags.DeclaredOnly,
110                                         virtual_method_filter, null);
111
112                                 if (current_type == TypeManager.object_type)
113                                         searching = false;
114                                 else {
115                                         current_type = current_type.BaseType;
116                                         if (!current_type.IsAbstract)
117                                                 searching = false;
118                                 }
119
120                                 if (mi.Count == 0)
121                                         continue;
122
123                                 if (mi.Count == 1 && !(mi [0] is MethodBase))
124                                         searching = false;
125                                 else 
126                                         list = TypeManager.CopyNewMethods (list, mi);
127                         } while (searching);
128
129                         if (list == null)
130                                 return null;
131                         
132                         for (int i = 0; i < list.Count; i++){
133                                 while (list.Count > i && !((MethodInfo) list [i]).IsAbstract)
134                                         list.RemoveAt (i);
135                         }
136
137                         if (list.Count == 0)
138                                 return null;
139
140                         return list;
141                 }
142
143                 PendingImplementation (TypeContainer container, MissingInterfacesInfo [] missing_ifaces, ArrayList abstract_methods, int total)
144                 {
145                         TypeBuilder type_builder = container.TypeBuilder;
146                         
147                         this.container = container;
148                         pending_implementations = new TypeAndMethods [total];
149
150                         int i = 0;
151                         if (abstract_methods != null) {
152                                 int count = abstract_methods.Count;
153                                 pending_implementations [i].methods = new MethodInfo [count];
154                                 pending_implementations [i].need_proxy = new MethodInfo [count];
155                                 
156                                 abstract_methods.CopyTo (pending_implementations [i].methods, 0);
157                                 pending_implementations [i].found = new bool [count];
158                                 pending_implementations [i].args = new Type [count][];
159                                 pending_implementations [i].mods = new Parameter.Modifier [count][];
160                                 pending_implementations [i].type = type_builder;
161
162                                 string indexer_name = TypeManager.IndexerPropertyName (type_builder);
163                                 pending_implementations [i].set_indexer_name = "set_" + indexer_name;
164                                 pending_implementations [i].get_indexer_name = "get_" + indexer_name;
165                                 
166                                 int j = 0;
167                                 foreach (MemberInfo m in abstract_methods) {
168                                         MethodInfo mi = (MethodInfo) m;
169                                         
170                                         ParameterData pd = TypeManager.GetParameterData (mi);
171                                         Type [] types = pd.Types;
172                                         
173                                         pending_implementations [i].args [j] = types;
174                                         pending_implementations [i].mods [j] = null;
175                                         if (pd.Count > 0) {
176                                                 Parameter.Modifier [] pm = new Parameter.Modifier [pd.Count];
177                                                 for (int k = 0; k < pd.Count; k++)
178                                                         pm [k] = pd.ParameterModifier (k);
179                                                 pending_implementations [i].mods [j] = pm;
180                                         }
181                                                 
182                                         j++;
183                                 }
184                                 ++i;
185                         }
186
187                         foreach (MissingInterfacesInfo missing in missing_ifaces) {
188                                 MethodInfo [] mi;
189                                 Type t = missing.Type;
190                                 
191                                 if (!t.IsInterface)
192                                         continue;
193
194                                 if (t is TypeBuilder){
195                                         TypeContainer iface;
196
197                                         iface = TypeManager.LookupInterface (t);
198                                         
199                                         mi = iface.GetMethods ();
200                                 } else 
201                                         mi = t.GetMethods ();
202                                 
203                                 int count = mi.Length;
204                                 pending_implementations [i].type = t;
205                                 pending_implementations [i].optional = missing.Optional;
206                                 pending_implementations [i].methods = mi;
207                                 pending_implementations [i].args = new Type [count][];
208                                 pending_implementations [i].mods = new Parameter.Modifier [count][];
209                                 pending_implementations [i].found = new bool [count];
210                                 pending_implementations [i].need_proxy = new MethodInfo [count];
211                                 string indexer_name = TypeManager.IndexerPropertyName (t);
212
213                                 pending_implementations [i].set_indexer_name = "set_" + indexer_name;
214                                 pending_implementations [i].get_indexer_name = "get_" + indexer_name;
215                                 
216                                 int j = 0;
217                                 foreach (MethodInfo m in mi){
218                                         pending_implementations [i].args [j] = Type.EmptyTypes;
219                                         pending_implementations [i].mods [j] = null;
220
221                                         // If there is a previous error, just ignore
222                                         if (m == null)
223                                                 continue;
224
225                                         ParameterData pd = TypeManager.GetParameterData (m);
226                                         pending_implementations [i].args [j] = pd.Types;
227                                         
228                                         if (pd.Count > 0){
229                                                 Parameter.Modifier [] pm = new Parameter.Modifier [pd.Count];
230                                                 for (int k = 0; k < pd.Count; k++)
231                                                         pm [k] = pd.ParameterModifier (k);
232                                                 pending_implementations [i].mods [j] = pm;
233                                         }
234                         
235                                         j++;
236                                 }
237                                 i++;
238                         }
239                 }
240
241                 struct MissingInterfacesInfo {
242                         public Type Type;
243                         public bool Optional;
244
245                         public MissingInterfacesInfo (Type t)
246                         {
247                                 Type = t;
248                                 Optional = false;
249                         }
250                 }
251
252                 static MissingInterfacesInfo [] EmptyMissingInterfacesInfo = new MissingInterfacesInfo [0];
253                 
254                 static MissingInterfacesInfo [] GetMissingInterfaces (TypeBuilder type_builder)
255                 {
256                         //
257                         // Notice that TypeBuilders will only return the interfaces that the Type
258                         // is supposed to implement, not all the interfaces that the type implements.
259                         //
260                         // Even better -- on MS it returns an empty array, no matter what.
261                         //
262                         // Completely broken.  So we do it ourselves!
263                         //
264                         Type [] impl = TypeManager.GetExplicitInterfaces (type_builder);
265
266                         if (impl == null || impl.Length == 0)
267                                 return EmptyMissingInterfacesInfo;
268
269                         MissingInterfacesInfo [] ret = new MissingInterfacesInfo [impl.Length];
270
271                         for (int i = 0; i < impl.Length; i++)
272                                 ret [i] = new MissingInterfacesInfo (impl [i]);
273
274                         // we really should not get here because Object doesnt implement any
275                         // interfaces. But it could implement something internal, so we have
276                         // to handle that case.
277                         if (type_builder.BaseType == null)
278                                 return ret;
279                         
280                         Type [] base_impls = TypeManager.GetInterfaces (type_builder.BaseType);
281                         
282                         foreach (Type t in base_impls) {
283                                 for (int i = 0; i < ret.Length; i ++) {
284                                         if (t == ret [i].Type) {
285                                                 ret [i].Optional = true;
286                                                 break;
287                                         }
288                                 }
289                         }
290                         return ret;
291                 }
292                 
293                 //
294                 // Factory method: if there are pending implementation methods, we return a PendingImplementation
295                 // object, otherwise we return null.
296                 //
297                 // Register method implementations are either abstract methods
298                 // flagged as such on the base class or interface methods
299                 //
300                 static public PendingImplementation GetPendingImplementations (TypeContainer container)
301                 {
302                         TypeBuilder type_builder = container.TypeBuilder;
303                         MissingInterfacesInfo [] missing_interfaces;
304                         Type b = type_builder.BaseType;
305
306                         missing_interfaces = GetMissingInterfaces (type_builder);
307
308                         //
309                         // If we are implementing an abstract class, and we are not
310                         // ourselves abstract, and there are abstract methods (C# allows
311                         // abstract classes that have no abstract methods), then allocate
312                         // one slot.
313                         //
314                         // We also pre-compute the methods.
315                         //
316                         bool implementing_abstract = ((b != null) && b.IsAbstract && !type_builder.IsAbstract);
317                         ArrayList abstract_methods = null;
318
319                         if (implementing_abstract){
320                                 abstract_methods = GetAbstractMethods (b);
321                                 
322                                 if (abstract_methods == null)
323                                         implementing_abstract = false;
324                         }
325                         
326                         int total = missing_interfaces.Length +  (implementing_abstract ? 1 : 0);
327                         if (total == 0)
328                                 return null;
329
330                         return new PendingImplementation (container, missing_interfaces, abstract_methods, total);
331                 }
332
333                 public enum Operation {
334                         //
335                         // If you change this, review the whole InterfaceMethod routine as there
336                         // are a couple of assumptions on these three states
337                         //
338                         Lookup, ClearOne, ClearAll
339                 }
340
341                 /// <summary>
342                 ///   Whether the specified method is an interface method implementation
343                 /// </summary>
344                 public MethodInfo IsInterfaceMethod (Type t, string name, Type ret_type, ParameterData args)
345                 {
346                         return InterfaceMethod (t, name, ret_type, args, Operation.Lookup, null);
347                 }
348
349                 public MethodInfo IsInterfaceIndexer (Type t, Type ret_type, ParameterData args)
350                 {
351                         return InterfaceMethod (t, null, ret_type, args, Operation.Lookup, null);
352                 }
353
354                 public void ImplementMethod (Type t, string name, Type ret_type, ParameterData args, bool clear_one) 
355                 {
356                         InterfaceMethod (t, name, ret_type, args,
357                                          clear_one ? Operation.ClearOne : Operation.ClearAll, null);
358                 }
359
360                 public void ImplementIndexer (Type t, MethodInfo mi, Type ret_type, ParameterData args, bool clear_one) 
361                 {
362                         InterfaceMethod (t, null, ret_type, args,
363                                          clear_one ? Operation.ClearOne : Operation.ClearAll, mi);
364                 }
365                 
366                 /// <remarks>
367                 ///   If a method in Type `t' (or null to look in all interfaces
368                 ///   and the base abstract class) with name `Name', return type `ret_type' and
369                 ///   arguments `args' implements an interface, this method will
370                 ///   return the MethodInfo that this method implements.
371                 ///
372                 ///   If `name' is null, we operate solely on the method's signature.  This is for
373                 ///   instance used when implementing indexers.
374                 ///
375                 ///   The `Operation op' controls whether to lookup, clear the pending bit, or clear
376                 ///   all the methods with the given signature.
377                 ///
378                 ///   The `MethodInfo need_proxy' is used when we're implementing an interface's
379                 ///   indexer in a class.  If the new indexer's IndexerName does not match the one
380                 ///   that was used in the interface, then we always need to create a proxy for it.
381                 ///
382                 /// </remarks>
383                 public MethodInfo InterfaceMethod (Type t, string name, Type ret_type, ParameterData args,
384                                                    Operation op, MethodInfo need_proxy)
385                 {
386                         int arg_len = args.Count;
387
388                         if (pending_implementations == null)
389                                 return null;
390
391                         foreach (TypeAndMethods tm in pending_implementations){
392                                 if (!(t == null || tm.type == t))
393                                         continue;
394
395                                 int method_count = tm.methods.Length;
396                                 MethodInfo m;
397                                 for (int i = 0; i < method_count; i++){
398                                         m = tm.methods [i];
399
400                                         if (m == null)
401                                                 continue;
402
403                                         string mname = TypeManager.GetMethodName (m);
404
405                                         //
406                                         // `need_proxy' is not null when we're implementing an
407                                         // interface indexer and this is Clear(One/All) operation.
408                                         //
409                                         // If `name' is null, then we do a match solely based on the
410                                         // signature and not on the name (this is done in the Lookup
411                                         // for an interface indexer).
412                                         //
413                                         if (name == null){
414                                                 if (mname != tm.get_indexer_name && mname != tm.set_indexer_name)
415                                                         continue;
416                                         } else if ((need_proxy == null) && (name != mname))
417                                                 continue;
418
419                                         if (!TypeManager.IsEqual (ret_type, m.ReturnType) &&
420                                             !(ret_type == null && m.ReturnType == TypeManager.void_type) &&
421                                             !(m.ReturnType == null && ret_type == TypeManager.void_type))
422                                                 continue;
423
424                                         //
425                                         // Check if we have the same parameters
426                                         //
427
428                                         if (tm.args [i] == null && arg_len != 0)
429                                                 continue;
430                                         if (tm.args [i] != null && tm.args [i].Length != arg_len)
431                                                 continue;
432
433                                         int j;
434
435                                         for (j = 0; j < arg_len; j++) {
436                                                 if (!TypeManager.IsEqual (tm.args [i][j], args.ParameterType (j)))
437                                                         break;
438                                                 if (tm.mods [i][j] == args.ParameterModifier (j))
439                                                         continue;
440                                                 // The modifiers are different, but if one of them
441                                                 // is a PARAMS modifier, and the other isn't, ignore
442                                                 // the difference.
443                                                 if (tm.mods [i][j] != Parameter.Modifier.PARAMS &&
444                                                     args.ParameterModifier (j) != Parameter.Modifier.PARAMS)
445                                                         break;
446                                         }
447                                         if (j != arg_len)
448                                                 continue;
449
450                                         if (op != Operation.Lookup){
451                                                 // If `t != null', then this is an explicitly interface
452                                                 // implementation and we can always clear the method.
453                                                 // `need_proxy' is not null if we're implementing an
454                                                 // interface indexer.  In this case, we need to create
455                                                 // a proxy if the implementation's IndexerName doesn't
456                                                 // match the IndexerName in the interface.
457                                                 bool name_matches = false;
458                                                 if (name == mname || mname == tm.get_indexer_name || mname == tm.set_indexer_name)
459                                                         name_matches = true;
460
461                                                 if ((t == null) && (need_proxy != null) && !name_matches)
462                                                         tm.need_proxy [i] = need_proxy;
463                                                 else 
464                                                         tm.methods [i] = null;
465                                         }
466                                         tm.found [i] = true;
467
468                                         //
469                                         // Lookups and ClearOne return
470                                         //
471                                         if (op != Operation.ClearAll)
472                                                 return m;
473                                 }
474
475                                 // If a specific type was requested, we can stop now.
476                                 if (tm.type == t)
477                                         return null;
478                         }
479                         return null;
480                 }
481
482                 /// <summary>
483                 ///   C# allows this kind of scenarios:
484                 ///   interface I { void M (); }
485                 ///   class X { public void M (); }
486                 ///   class Y : X, I { }
487                 ///
488                 ///   For that case, we create an explicit implementation function
489                 ///   I.M in Y.
490                 /// </summary>
491                 void DefineProxy (Type iface, MethodInfo base_method, MethodInfo iface_method,
492                                   Type [] args)
493                 {
494                         MethodBuilder proxy;
495
496                         string proxy_name = SimpleName.RemoveGenericArity (iface.Name) + '.' + iface_method.Name;
497
498                         proxy = container.TypeBuilder.DefineMethod (
499                                 proxy_name,
500                                 MethodAttributes.HideBySig |
501                                 MethodAttributes.NewSlot |
502                                 MethodAttributes.Virtual,
503                                 CallingConventions.Standard | CallingConventions.HasThis,
504                                 base_method.ReturnType, args);
505
506                         ParameterData pd = TypeManager.GetParameterData (iface_method);
507                         proxy.DefineParameter (0, ParameterAttributes.None, "");
508                         for (int i = 0; i < pd.Count; i++) {
509                                 string name = pd.ParameterName (i);
510                                 ParameterAttributes attr = Parameter.GetParameterAttributes (pd.ParameterModifier (i));
511                                 proxy.DefineParameter (i + 1, attr, name);
512                         }
513
514                         int top = args.Length;
515                         ILGenerator ig = proxy.GetILGenerator ();
516
517                         for (int i = 0; i <= top; i++)
518                                 ParameterReference.EmitLdArg (ig, i);
519
520                         ig.Emit (OpCodes.Call, base_method);
521                         ig.Emit (OpCodes.Ret);
522
523                         container.TypeBuilder.DefineMethodOverride (proxy, iface_method);
524                 }
525                 
526                 /// <summary>
527                 ///   This function tells whether one of our base classes implements
528                 ///   the given method (which turns out, it is valid to have an interface
529                 ///   implementation in a base
530                 /// </summary>
531                 bool BaseImplements (Type iface_type, MethodInfo mi)
532                 {
533                         MethodSignature ms;
534                         
535                         Type [] args = TypeManager.GetParameterData (mi).Types;
536                         ms = new MethodSignature (mi.Name, mi.ReturnType, args);
537                         MemberList list = TypeContainer.FindMembers (
538                                 container.TypeBuilder.BaseType, MemberTypes.Method | MemberTypes.Property,
539                                 BindingFlags.Public | BindingFlags.Instance,
540                                 MethodSignature.method_signature_filter, ms);
541
542                         if (list.Count == 0)
543                                 return false;
544
545                         if (TypeManager.ImplementsInterface (container.TypeBuilder.BaseType, iface_type))
546                                 return true;
547
548                         //
549                         // FIXME: We should be creating fewer proxies.  The runtime can handle most cases.  
550                         //        At worst, if we can't avoid creating the proxy, we may need to make the 
551                         //        proxy use Callvirt.
552                         //
553                         MethodInfo base_method = (MethodInfo) list [0];
554
555                         if (base_method.DeclaringType.IsInterface)
556                                 return false;
557
558                         if (!base_method.IsAbstract && !base_method.IsVirtual)
559                                 DefineProxy (iface_type, base_method, mi, args);
560
561                         return true;
562                 }
563
564                 /// <summary>
565                 ///   Verifies that any pending abstract methods or interface methods
566                 ///   were implemented.
567                 /// </summary>
568                 public bool VerifyPendingMethods ()
569                 {
570                         int top = pending_implementations.Length;
571                         bool errors = false;
572                         int i;
573                         
574                         for (i = 0; i < top; i++){
575                                 Type type = pending_implementations [i].type;
576                                 int j = 0;
577
578                                 bool base_implements_type = type.IsInterface &&
579                                         container.TypeBuilder.BaseType != null &&
580                                         TypeManager.ImplementsInterface (container.TypeBuilder.BaseType, type);
581
582                                 foreach (MethodInfo mi in pending_implementations [i].methods){
583                                         if (mi == null)
584                                                 continue;
585
586                                         if (type.IsInterface){
587                                                 MethodInfo need_proxy =
588                                                         pending_implementations [i].need_proxy [j];
589
590                                                 if (need_proxy != null) {
591                                                         Type [] args = TypeManager.GetParameterData (mi).Types;
592                                                         DefineProxy (type, need_proxy, mi, args);
593                                                         continue;
594                                                 }
595
596                                                 if (base_implements_type || BaseImplements (type, mi))
597                                                         continue;
598                                                 
599                                                 if (pending_implementations [i].optional)
600                                                         continue;
601
602                                                 Report.SymbolRelatedToPreviousError (mi);
603                                                 if (pending_implementations [i].found [j]) {
604                                                         if (mi.IsSpecialName) {
605                                                                 string name = TypeManager.CSharpName (mi.DeclaringType) + '.' + mi.Name.Substring (4);
606                                                                 Report.Error (551, container.Location, "Explicit interface implementation `{0}.{1}' is missing accessor `{2}'",
607                                                                         container.GetSignatureForError (), name, TypeManager.CSharpSignature (mi, true));
608                                                         } else {
609                                                                 string[] methodLabel = TypeManager.CSharpSignature (mi).Split ('.');
610                                                                 Report.Error (536, container.Location,
611                                                                         "`{0}' does not implement interface member `{1}'. `{2}.{3}' " +
612                                                                         "is either static, not public, or has the wrong return type",
613                                                                         container.Name, TypeManager.CSharpSignature (mi),
614                                                                         container.Name, methodLabel[methodLabel.Length - 1]);
615                                                         }
616                                                 }
617                                                 else {
618                                                         Report.Error (535, container.Location, "`{0}' does not implement interface member `{1}'",
619                                                                 container.GetSignatureForError (), TypeManager.CSharpSignature (mi));
620                                                 }
621                                         } else {
622                                                 Report.Error (534, container.Location, "`{0}' does not implement inherited abstract member `{1}'",
623                                                         container.GetSignatureForError (), TypeManager.CSharpSignature (mi, true));
624                                         }
625                                         errors = true;
626                                         j++;
627                                 }
628                         }
629                         return errors;
630                 }
631         } /* end of class */
632 }