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