2001-11-22 Miguel de Icaza <miguel@ximian.com>
[mono.git] / mcs / mcs / interface.cs
1 //
2 // interface.cs: Interface handler
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //
6 // Licensed under the terms of the GNU GPL
7 //
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
9 //
10
11 using System.Collections;
12 using System;
13 using System.IO;
14 using System.Reflection;
15 using System.Reflection.Emit;
16
17 namespace Mono.CSharp {
18
19         /// <summary>
20         ///   Interfaces
21         /// </summary>
22         public class Interface : DeclSpace {
23                 const MethodAttributes interface_method_attributes =
24                         MethodAttributes.Public |
25                         MethodAttributes.Abstract |
26                         MethodAttributes.HideBySig |
27                         MethodAttributes.NewSlot |
28                         MethodAttributes.Virtual;
29
30                 const MethodAttributes property_attributes =
31                         MethodAttributes.Public |
32                         MethodAttributes.Abstract |
33                         MethodAttributes.HideBySig |
34                         MethodAttributes.NewSlot |
35                         MethodAttributes.SpecialName |
36                         MethodAttributes.Virtual;
37                 
38                 ArrayList bases;
39                 int mod_flags;
40                 
41                 ArrayList defined_method;
42                 ArrayList defined_indexer;
43                 ArrayList defined_events;
44                 ArrayList defined_properties;
45
46                 ArrayList method_builders;
47                 ArrayList property_builders;
48                 
49                 TypeContainer parent;
50
51                 Attributes OptAttributes;
52
53                 public readonly RootContext RootContext;
54                 
55                 // These will happen after the semantic analysis
56                 
57                 // Hashtable defined_indexers;
58                 // Hashtable defined_methods;
59                 
60                 /// <summary>
61                 ///   Modifiers allowed in a class declaration
62                 /// </summary>
63                 public const int AllowedModifiers =
64                         Modifiers.NEW |
65                         Modifiers.PUBLIC |
66                         Modifiers.PROTECTED |
67                         Modifiers.INTERNAL |
68                         Modifiers.PRIVATE;
69
70                 public Interface (RootContext rc, TypeContainer parent, string name, int mod, Attributes attrs, Location l)
71                         : base (name, l)
72                 {
73                         this.mod_flags = Modifiers.Check (AllowedModifiers, mod, Modifiers.PRIVATE);
74                         this.parent = parent;
75                         OptAttributes = attrs;
76                         RootContext = rc;
77                         
78                         method_builders = new ArrayList ();
79                         property_builders = new ArrayList ();
80                 }
81
82                 public AdditionResult AddMethod (InterfaceMethod imethod)
83                 {
84                         string name = imethod.Name;
85                         Object value = defined_names [name];
86
87                         if (value != null){
88                                 if (!(value is InterfaceMethod))
89                                         return AdditionResult.NameExists;
90                         } 
91
92                         if (defined_method == null)
93                                 defined_method = new ArrayList ();
94
95                         defined_method.Add (imethod);
96                         if (value == null)
97                                 DefineName (name, imethod);
98                         
99                         return AdditionResult.Success;
100                 }
101
102                 public AdditionResult AddProperty (InterfaceProperty iprop)
103                 {
104                         AdditionResult res;
105                         string name = iprop.Name;
106
107                         if ((res = IsValid (name)) != AdditionResult.Success)
108                                 return res;
109
110                         DefineName (name, iprop);
111
112                         if (defined_properties == null)
113                                 defined_properties = new ArrayList ();
114
115                         defined_properties.Add (iprop);
116                         return AdditionResult.Success;
117                 }
118
119                 public AdditionResult AddEvent (InterfaceEvent ievent)
120                 {
121                         string name = ievent.Name;
122                         AdditionResult res;
123                         
124                         if ((res = IsValid (name)) != AdditionResult.Success)
125                                 return res;
126
127                         DefineName (name, ievent);
128
129                         if (defined_events == null)
130                                 defined_events = new ArrayList ();
131
132                         defined_events.Add (ievent);
133                         return AdditionResult.Success;
134                 }
135
136                 public bool AddIndexer (InterfaceIndexer iindexer)
137                 {
138                         if (defined_indexer == null)
139                                 defined_indexer = new ArrayList ();
140                         
141                         defined_indexer.Add (iindexer);
142                         return true;
143                 }
144                 
145                 public ArrayList InterfaceMethods {
146                         get {
147                                 return defined_method;
148                         }
149                 }
150
151                 public ArrayList InterfaceProperties {
152                         get {
153                                 return defined_properties;
154                         }
155                 }
156
157                 public ArrayList InterfaceEvents {
158                         get {
159                                 return defined_events;
160                         }
161                 }
162
163                 public ArrayList InterfaceIndexers {
164                         get {
165                                 return defined_indexer;
166                         }
167                 }
168
169                 public int ModFlags {
170                         get {
171                                 return mod_flags;
172                         }
173                 }
174                 
175                 public ArrayList Bases {
176                         get {
177                                 return bases;
178                         }
179
180                         set {
181                                 bases = value;
182                         }
183                 }
184
185                 public bool IsTopLevel {
186                         get {
187                                 if (parent != null){
188                                         if (parent.Parent == null)
189                                                 return true;
190                                 }
191                                 return false;
192                         }
193                 }
194
195                 public virtual TypeAttributes InterfaceAttr {
196                         get {
197                                 TypeAttributes x = 0;
198
199                                 if ((mod_flags & Modifiers.PUBLIC) != 0)
200                                         x |= TypeAttributes.Public;
201                                 else if ((mod_flags & Modifiers.PRIVATE) != 0)
202                                         x |= TypeAttributes.NotPublic;
203                                 
204                                 if (IsTopLevel == false) {
205                                         
206                                         if ((mod_flags & Modifiers.PROTECTED) != 0
207                                             && (mod_flags & Modifiers.INTERNAL) != 0)
208                                                 x |= TypeAttributes.NestedFamORAssem;
209                                         
210                                         if ((mod_flags & Modifiers.PROTECTED) != 0)
211                                                 x |= TypeAttributes.NestedFamily;
212                                         
213                                         if ((mod_flags & Modifiers.INTERNAL) != 0)
214                                                 x |= TypeAttributes.NestedAssembly;
215                                         
216                                 }
217                                 
218                                 if ((mod_flags & Modifiers.ABSTRACT) != 0)
219                                         x |= TypeAttributes.Abstract;
220                                 
221                                 if ((mod_flags & Modifiers.SEALED) != 0)
222                                         x |= TypeAttributes.Sealed;
223
224                                 return x;
225                         }
226                 }
227                 
228                 void Error111 (InterfaceMemberBase ib)
229                 {
230                         Report.Error (
231                                 111,
232                                 "Interface `" + Name + "' already contains a definition with the " +
233                                 "same return value and parameter types for member `" + ib.Name + "'");
234                 }
235
236                 bool RegisterMethod (MethodBase mb, Type [] types)
237                 {
238                         if (!TypeManager.RegisterMethod (mb, types))
239                                 return false;
240
241                         method_builders.Add (mb);
242                         return true;
243                 }
244
245                 public MethodInfo [] GetMethods ()
246                 {
247                         int n = method_builders.Count;
248                         MethodInfo [] mi = new MethodInfo [n];
249                         
250                         method_builders.CopyTo (mi, 0);
251
252                         return mi;
253                 }
254
255                 // Hack around System.Reflection as found everywhere else
256                 public MemberInfo [] FindMembers (MemberTypes mt, BindingFlags bf, MemberFilter filter, object criteria)
257                 {
258                         ArrayList members = new ArrayList ();
259
260                         if ((mt & MemberTypes.Method) != 0) {
261                                 foreach (MethodBuilder mb in method_builders)
262                                         if (filter (mb, criteria))
263                                                 members.Add (mb);
264                         }
265
266                         if ((mt & MemberTypes.Property) != 0) {
267                                 foreach (PropertyBuilder pb in property_builders)
268                                         if (filter (pb, criteria))
269                                                 members.Add (pb);
270                         }
271
272                         // The rest of the cases, if any, are unhandled at present.
273
274                         int count = members.Count;
275
276                         if (count > 0) {
277                                 MemberInfo [] mi = new MemberInfo [count];
278                                 members.CopyTo (mi, 0);
279                                 return mi;
280                         }
281
282                         return null;
283                 }
284                 
285                 
286                 //
287                 // Populates the methods in the interface
288                 //
289                 void PopulateMethod (InterfaceMethod im)
290                 {
291                         Type return_type = parent.LookupType (im.ReturnType, true);
292                         Type [] arg_types = im.ParameterTypes (parent);
293                         MethodBuilder mb;
294                         Parameter [] p;
295                         int i;
296                         
297                         //
298                         // Create the method
299                         //
300                         mb = TypeBuilder.DefineMethod (
301                                 im.Name, interface_method_attributes,
302                                 return_type, arg_types);
303                         
304                         if (!RegisterMethod (mb, arg_types)) {
305                                 Error111 (im);
306                                 return;
307                         }
308                         
309                         //
310                         // Define each type attribute (in/out/ref) and
311                         // the argument names.
312                         //
313                         p = im.Parameters.FixedParameters;
314                         if (p != null){
315                                 for (i = 0; i < p.Length; i++)
316                                         mb.DefineParameter (i + 1, p [i].Attributes, p [i].Name);
317
318                                 if (i != arg_types.Length)
319                                         Console.WriteLine ("Implement the type definition for params");
320                         }
321                 }
322
323                 //
324                 // Populates the properties in the interface
325                 //
326                 void PopulateProperty (InterfaceProperty ip)
327                 {
328                         PropertyBuilder pb;
329                         MethodBuilder mb;
330                         Type prop_type = parent.LookupType (ip.Type, true);
331                         Type [] setter_args = new Type [1];
332
333                         setter_args [0] = prop_type;
334
335                         //
336                         // FIXME: properties are missing the following
337                         // flags: hidebysig newslot specialname
338                         // 
339                         pb = TypeBuilder.DefineProperty (
340                                 ip.Name, PropertyAttributes.None,
341                                 prop_type, null);
342
343                         if (ip.HasGet){
344                                 mb = TypeBuilder.DefineMethod (
345                                         "get_" + ip.Name, property_attributes ,
346                                         prop_type, null);
347
348                                 //
349                                 // HACK because System.Reflection.Emit is lame
350                                 //
351                                 if (!RegisterMethod (mb, null)) {
352                                         Error111 (ip);
353                                         return;
354                                 }
355                                 
356                                 pb.SetGetMethod (mb);
357                         }
358
359                         if (ip.HasSet){
360                                 setter_args [0] = prop_type;
361
362                                 mb = TypeBuilder.DefineMethod (
363                                         "set_" + ip.Name, property_attributes,
364                                         null, setter_args);
365
366                                 mb.DefineParameter (1, ParameterAttributes.None, "value");
367                                 pb.SetSetMethod (mb);
368
369                                 //
370                                 // HACK because System.Reflection.Emit is lame
371                                 //
372                                 if (!RegisterMethod (mb, setter_args)) {
373                                         Error111 (ip);
374                                         return;
375                                 }
376                         }
377
378                         property_builders.Add (pb);
379                 }
380
381                 //
382                 // Populates the events in the interface
383                 //
384                 void PopulateEvent (InterfaceEvent ie)
385                 {
386                         //
387                         // FIXME: We need to do this after delegates have been
388                         // declared or we declare them recursively.
389                         //
390                 }
391
392                 //
393                 // Populates the indexers in the interface
394                 //
395                 void PopulateIndexer (InterfaceIndexer ii)
396                 {
397                         PropertyBuilder pb;
398                         Type prop_type = parent.LookupType (ii.Type, true);
399                         Type [] arg_types = ii.ParameterTypes (parent);
400                         Type [] value_arg_types;
401
402                         //
403                         // Sets up the extra invisible `value' argument for setters.
404                         // 
405                         if (arg_types != null){
406                                 int count = arg_types.Length;
407                                 value_arg_types = new Type [count + 1];
408
409                                 arg_types.CopyTo (value_arg_types, 0);
410                                 value_arg_types [count] = prop_type;
411                         } else {
412                                 value_arg_types = new Type [1];
413
414                                 value_arg_types [1] = prop_type;
415                         }
416
417                         pb = TypeBuilder.DefineProperty (
418                                 "Item", PropertyAttributes.None,
419                                 prop_type, arg_types);
420
421                         if (ii.HasGet){
422                                 MethodBuilder get_item;
423                                 Parameter [] p = ii.Parameters.FixedParameters;
424                                 
425                                 get_item = TypeBuilder.DefineMethod (
426                                         "get_Item", property_attributes, prop_type, arg_types);
427                                 pb.SetGetMethod (get_item);
428                                 //
429                                 // HACK because System.Reflection.Emit is lame
430                                 //
431                                 if (!RegisterMethod (get_item, arg_types)) {
432                                         Error111 (ii);
433                                         return;
434                                 }
435
436                                 if (p != null){
437                                         for (int i = 0; i < p.Length; i++)
438                                                 get_item.DefineParameter (
439                                                         i + 1,
440                                                         p [i].Attributes, p [i].Name);
441                                 }
442                         }
443
444                         if (ii.HasSet){
445                                 Parameter [] p = ii.Parameters.FixedParameters;
446                                 MethodBuilder set_item;
447                                 int i = 0;
448                                 
449                                 set_item = TypeBuilder.DefineMethod (
450                                         "set_Item", property_attributes, null, value_arg_types);
451                                 pb.SetSetMethod (set_item);
452                                 //
453                                 // HACK because System.Reflection.Emit is lame
454                                 //
455                                 if (!RegisterMethod (set_item, value_arg_types)) {
456                                         Error111 (ii);
457                                         return;
458                                 }
459
460                                 if (p != null){
461                                         for (; i < p.Length; i++)
462                                                 set_item.DefineParameter (
463                                                         i + 1,
464                                                         p [i].Attributes, p [i].Name);
465                                 }
466                                 set_item.DefineParameter (i + 1, ParameterAttributes.None, "value");
467                         }
468                 }
469
470                 /// <summary>
471                 ///   Performs the semantic analysis for all the interface members
472                 ///   that were declared
473                 /// </summary>
474                 bool SemanticAnalysis ()
475                 {
476                         Hashtable methods = new Hashtable ();
477
478                         
479                         if (defined_method != null){
480                                 foreach (InterfaceMethod im in defined_method){
481                                         string sig = im.GetSignature (parent);
482                                         
483                                         //
484                                         // If there was an undefined Type on the signatures
485                                         // 
486                                         if (sig == null)
487                                                 continue;
488                                         
489                                         if (methods [sig] != null){
490                                                 Error111 (im);
491                                                 return false;
492                                         }
493                                 }
494                         }
495
496                         //
497                         // FIXME: Here I should check i
498                         // 
499                         return true;
500                 }
501
502                 //
503                 // Returns the Type that represents the interface whose name
504                 // is `name'.
505                 //
506                 
507                 Type GetInterfaceTypeByName (object builder, string name)
508                 {
509                         Interface parent;
510                         Type t = RootContext.TypeManager.LookupType (name);
511                         
512                         if (t != null) {
513
514                                 if (t.IsInterface)
515                                         return t;
516                                 
517                                 string cause;
518                                 
519                                 if (t.IsValueType)
520                                         cause = "is a struct";
521                                 else if (t.IsClass) 
522                                         cause = "is a class";
523                                 else
524                                         cause = "Should not happen.";
525
526                                 Report.Error (527, "`"+name+"' " + cause + ", need an interface instead");
527                                 
528                                 return null;
529                         }
530
531                         Tree tree = RootContext.Tree;
532                         parent = (Interface) tree.Interfaces [name];
533                         if (parent == null){
534                                 string cause = "is undefined";
535                                 
536                                 if (tree.Classes [name] != null)
537                                         cause = "is a class";
538                                 else if (tree.Structs [name] != null)
539                                         cause = "is a struct";
540                                 
541                                 Report.Error (527, "`"+name+"' " + cause + ", need an interface instead");
542                                 return null;
543                         }
544                         
545                         t = parent.DefineInterface (builder);
546                         if (t == null){
547                                 Report.Error (529,
548                                               "Inherited interface `"+name+"' is circular");
549                                 return null;
550                         }
551
552                         return t;
553                 }
554                 
555                 //
556                 // Returns the list of interfaces that this interface implements
557                 // Or null if it does not implement any interface.
558                 //
559                 // Sets the error boolean accoringly.
560                 //
561                 Type [] GetInterfaceBases (object builder, out bool error)
562                 {
563                         Type [] tbases;
564                         int i;
565
566                         error = false;
567                         if (Bases == null)
568                                 return null;
569                         
570                         tbases = new Type [Bases.Count];
571                         i = 0;
572
573                         foreach (string name in Bases){
574                                 Type t;
575                                 
576                                 t = GetInterfaceTypeByName (builder, name);
577                                 if (t == null){
578                                         error = true;
579                                         return null;
580                                 }
581                                 
582                                 tbases [i++] = t;
583                         }
584                         
585                         return tbases;
586                 }
587                 
588                 //
589                 // <summary>
590                 //  Defines the Interface in the appropriate ModuleBuilder or TypeBuilder
591                 // </summary>
592                 // TODO:
593                 //   Rework the way we recurse, because for recursive
594                 //   definitions of interfaces (A:B and B:A) we report the
595                 //   error twice, rather than once.  
596                 
597                 public TypeBuilder DefineInterface (object parent_builder)
598                 {
599                         Type [] ifaces;
600                         bool error;
601
602                         if (InTransit)
603                                 return null;
604                         
605                         InTransit = true;
606                         
607                         ifaces = GetInterfaceBases (parent_builder, out error);
608
609                         if (error)
610                                 return null;
611
612                         if (parent_builder is ModuleBuilder) {
613                                 ModuleBuilder builder = (ModuleBuilder) parent_builder;
614                                 
615                                 TypeBuilder = builder.DefineType (Name,
616                                                                   TypeAttributes.Interface |
617                                                                   InterfaceAttr |
618                                                                   TypeAttributes.Abstract,
619                                                                   null,   // Parent Type
620                                                                   ifaces);
621                         } else {
622                                 TypeBuilder builder = (TypeBuilder) parent_builder;
623
624                                 TypeBuilder = builder.DefineNestedType (Name,
625                                                                         TypeAttributes.Interface |
626                                                                         InterfaceAttr |
627                                                                         TypeAttributes.Abstract,
628                                                                         null,   // Parent Type
629                                                                         ifaces);
630                         }
631                         
632                         RootContext.TypeManager.AddUserInterface (Name, TypeBuilder, this);
633                         
634                         InTransit = false;
635                         
636                         return TypeBuilder;
637                 }
638                 
639                 /// <summary>
640                 ///   Performs semantic analysis, and then generates the IL interfaces
641                 /// </summary>
642                 public void Populate ()
643                 {
644                         if (!SemanticAnalysis ())
645                                 return;
646
647                         if (defined_method != null){
648                                 foreach (InterfaceMethod im in defined_method)
649                                         PopulateMethod (im);
650                         }
651
652                         if (defined_properties != null){
653                                 foreach (InterfaceProperty ip in defined_properties)
654                                         PopulateProperty (ip);
655                         }
656
657                         if (defined_events != null)
658                                 foreach (InterfaceEvent ie in defined_events)
659                                         PopulateEvent (ie);
660
661                         if (defined_indexer != null)
662                                 foreach (InterfaceIndexer ii in defined_indexer)
663                                         PopulateIndexer (ii);
664                 }
665
666                 public void CloseType ()
667                 {
668                         TypeBuilder.CreateType ();
669                 }
670                 
671         }
672
673         public class InterfaceMemberBase {
674                 public readonly string Name;
675                 public readonly bool IsNew;
676                 public Attributes OptAttributes;
677                 
678                 public InterfaceMemberBase (string name, bool is_new, Attributes attrs)
679                 {
680                         Name = name;
681                         IsNew = is_new;
682                         OptAttributes = attrs;
683                 }
684         }
685         
686         public class InterfaceProperty : InterfaceMemberBase {
687                 public readonly bool HasSet;
688                 public readonly bool HasGet;
689                 public readonly string Type;
690                 public readonly string type;
691                 
692                 public InterfaceProperty (string type, string name,
693                                           bool is_new, bool has_get, bool has_set, Attributes attrs)
694                         : base (name, is_new, attrs)
695                 {
696                         Type = type;
697                         HasGet = has_get;
698                         HasSet = has_set;
699                 }
700         }
701
702         public class InterfaceEvent : InterfaceMemberBase {
703                 public readonly string Type;
704                 
705                 public InterfaceEvent (string type, string name, bool is_new, Attributes attrs)
706                         : base (name, is_new, attrs)
707                 {
708                         Type = type;
709                 }
710         }
711         
712         public class InterfaceMethod : InterfaceMemberBase {
713                 public readonly string     ReturnType;
714                 public readonly Parameters Parameters;
715                 
716                 public InterfaceMethod (string return_type, string name, bool is_new, Parameters args, Attributes attrs)
717                         : base (name, is_new, attrs)
718                 {
719                         this.ReturnType = return_type;
720                         this.Parameters = args;
721                 }
722
723                 /// <summary>
724                 ///   Returns the signature for this interface method
725                 /// </summary>
726                 public string GetSignature (TypeContainer tc)
727                 {
728                         Type ret = tc.LookupType (ReturnType, false);
729                         string args = Parameters.GetSignature (tc);
730
731                         if ((ret == null) || (args == null))
732                                 return null;
733                         
734                         return (IsNew ? "new-" : "") + ret.FullName + "(" + args + ")";
735                 }
736
737                 public Type [] ParameterTypes (TypeContainer tc)
738                 {
739                         return Parameters.GetParameterInfo (tc);
740                 }
741         }
742
743         public class InterfaceIndexer : InterfaceMemberBase {
744                 public readonly bool HasGet, HasSet;
745                 public readonly Parameters Parameters;
746                 public readonly string Type;
747                 
748                 public InterfaceIndexer (string type, Parameters args, bool do_get, bool do_set, bool is_new,
749                                          Attributes attrs)
750                         : base ("", is_new, attrs)
751                 {
752                         Type = type;
753                         Parameters = args;
754                         HasGet = do_get;
755                         HasSet = do_set;
756                 }
757
758                 public Type [] ParameterTypes (TypeContainer tc)
759                 {
760                         return Parameters.GetParameterInfo (tc);
761                 }
762         }
763 }