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