2001-10-31 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 (InterfaceMethod im)
226                 {
227                         Report.Error (
228                                 111,
229                                 "Interface `" + Name + "' already contains a definition with the " +
230                                 "same return value and paramenter types for method `" + im.Name + "'");
231                 }
232
233                 void RegisterMethod (MethodBase mb, Type [] types)
234                 {
235                         TypeManager.RegisterMethod (mb, types);
236                         method_builders.Add (mb);
237                 }
238
239                 public MethodInfo [] GetMethods ()
240                 {
241                         int n = method_builders.Count;
242                         MethodInfo [] mi = new MethodInfo [n];
243                         
244                         method_builders.CopyTo (mi, 0);
245
246                         return mi;
247                 }
248
249                 // Hack around System.Reflection as found everywhere else
250                 public MemberInfo [] FindMembers (MemberTypes mt, BindingFlags bf, MemberFilter filter, object criteria)
251                 {
252                         ArrayList members = new ArrayList ();
253
254                         if ((mt & MemberTypes.Method) != 0) {
255                                 foreach (MethodBuilder mb in method_builders)
256                                         if (filter (mb, criteria))
257                                                 members.Add (mb);
258                         }
259
260                         if ((mt & MemberTypes.Property) != 0) {
261                                 foreach (PropertyBuilder pb in property_builders)
262                                         if (filter (pb, criteria))
263                                                 members.Add (pb);
264                         }
265
266                         // The rest of the cases, if any, are unhandled at present.
267
268                         int count = members.Count;
269
270                         if (count > 0) {
271                                 MemberInfo [] mi = new MemberInfo [count];
272                                 members.CopyTo (mi, 0);
273                                 return mi;
274                         }
275
276                         return null;
277                 }
278                 
279                 
280                 //
281                 // Populates the methods in the interface
282                 //
283                 void PopulateMethod (InterfaceMethod im)
284                 {
285                         Type return_type = parent.LookupType (im.ReturnType, true);
286                         Type [] arg_types = im.ParameterTypes (parent);
287                         MethodBuilder mb;
288                         Parameter [] p;
289                         int i;
290                         
291                         //
292                         // Create the method
293                         //
294                         mb = TypeBuilder.DefineMethod (
295                                 im.Name, interface_method_attributes,
296                                 return_type, arg_types);
297                         
298                         RegisterMethod (mb, arg_types);
299                         
300                         //
301                         // Define each type attribute (in/out/ref) and
302                         // the argument names.
303                         //
304                         p = im.Parameters.FixedParameters;
305                         if (p != null){
306                                 for (i = 0; i < p.Length; i++)
307                                         mb.DefineParameter (i + 1, p [i].Attributes, p [i].Name);
308
309                                 if (i != arg_types.Length)
310                                         Console.WriteLine ("Implement the type definition for params");
311                         }
312                 }
313
314                 //
315                 // Populates the properties in the interface
316                 //
317                 void PopulateProperty (InterfaceProperty ip)
318                 {
319                         PropertyBuilder pb;
320                         MethodBuilder mb;
321                         Type prop_type = parent.LookupType (ip.Type, true);
322                         Type [] setter_args = new Type [1];
323
324                         setter_args [0] = prop_type;
325
326                         //
327                         // FIXME: properties are missing the following
328                         // flags: hidebysig newslot specialname
329                         // 
330                         pb = TypeBuilder.DefineProperty (
331                                 ip.Name, PropertyAttributes.None,
332                                 prop_type, null);
333
334                         if (ip.HasGet){
335                                 mb = TypeBuilder.DefineMethod (
336                                         "get_" + ip.Name, property_attributes ,
337                                         prop_type, null);
338
339                                 //
340                                 // HACK because System.Reflection.Emit is lame
341                                 //
342                                 RegisterMethod (mb, null);
343                                 
344                                 pb.SetGetMethod (mb);
345                         }
346
347                         if (ip.HasSet){
348                                 setter_args [0] = prop_type;
349
350                                 mb = TypeBuilder.DefineMethod (
351                                         "set_" + ip.Name, property_attributes,
352                                         null, setter_args);
353
354                                 mb.DefineParameter (1, ParameterAttributes.None, "value");
355                                 pb.SetSetMethod (mb);
356
357                                 //
358                                 // HACK because System.Reflection.Emit is lame
359                                 //
360                                 RegisterMethod (mb, setter_args);
361                         }
362
363                         property_builders.Add (pb);
364                 }
365
366                 //
367                 // Populates the events in the interface
368                 //
369                 void PopulateEvent (InterfaceEvent ie)
370                 {
371                         //
372                         // FIXME: We need to do this after delegates have been
373                         // declared or we declare them recursively.
374                         //
375                 }
376
377                 //
378                 // Populates the indexers in the interface
379                 //
380                 void PopulateIndexer (InterfaceIndexer ii)
381                 {
382                         PropertyBuilder pb;
383                         Type prop_type = parent.LookupType (ii.Type, true);
384                         Type [] arg_types = ii.ParameterTypes (parent);
385                         Type [] value_arg_types;
386
387                         //
388                         // Sets up the extra invisible `value' argument for setters.
389                         // 
390                         if (arg_types != null){
391                                 int count = arg_types.Length;
392                                 value_arg_types = new Type [count + 1];
393
394                                 arg_types.CopyTo (value_arg_types, 0);
395                                 value_arg_types [count] = prop_type;
396                         } else {
397                                 value_arg_types = new Type [1];
398
399                                 value_arg_types [1] = prop_type;
400                         }
401
402                         pb = TypeBuilder.DefineProperty (
403                                 "Item", PropertyAttributes.None,
404                                 prop_type, arg_types);
405
406                         if (ii.HasGet){
407                                 MethodBuilder get_item;
408                                 Parameter [] p = ii.Parameters.FixedParameters;
409                                 
410                                 get_item = TypeBuilder.DefineMethod (
411                                         "get_Item", property_attributes, prop_type, arg_types);
412                                 pb.SetGetMethod (get_item);
413                                 //
414                                 // HACK because System.Reflection.Emit is lame
415                                 //
416                                 RegisterMethod (get_item, arg_types);
417
418                                 if (p != null){
419                                         for (int i = 0; i < p.Length; i++)
420                                                 get_item.DefineParameter (
421                                                         i + 1,
422                                                         p [i].Attributes, p [i].Name);
423                                 }
424                         }
425
426                         if (ii.HasSet){
427                                 Parameter [] p = ii.Parameters.FixedParameters;
428                                 MethodBuilder set_item;
429                                 int i = 0;
430                                 
431                                 set_item = TypeBuilder.DefineMethod (
432                                         "set_Item", property_attributes, null, value_arg_types);
433                                 pb.SetSetMethod (set_item);
434                                 //
435                                 // HACK because System.Reflection.Emit is lame
436                                 //
437                                 RegisterMethod (set_item, value_arg_types);
438
439                                 if (p != null){
440                                         for (; i < p.Length; i++)
441                                                 set_item.DefineParameter (
442                                                         i + 1,
443                                                         p [i].Attributes, p [i].Name);
444                                 }
445                                 set_item.DefineParameter (i + 1, ParameterAttributes.None, "value");
446                         }
447                 }
448
449                 // <summary>
450                 //   Performs the semantic analysis for all the interface members
451                 //   that were declared
452                 // </summary>
453                 bool SemanticAnalysis ()
454                 {
455                         Hashtable methods = new Hashtable ();
456
457                         
458                         if (defined_method != null){
459                                 foreach (InterfaceMethod im in defined_method){
460                                         string sig = im.GetSignature (parent);
461                                         
462                                         //
463                                         // If there was an undefined Type on the signatures
464                                         // 
465                                         if (sig == null)
466                                                 continue;
467                                         
468                                         if (methods [sig] != null){
469                                                 Error111 (im);
470                                                 return false;
471                                         }
472                                 }
473                         }
474
475                         //
476                         // FIXME: Here I should check i
477                         // 
478                         return true;
479                 }
480
481                 //
482                 // Returns the Type that represents the interface whose name
483                 // is `name'.
484                 //
485                 
486                 Type GetInterfaceTypeByName (object builder, string name)
487                 {
488                         Interface parent;
489                         Type t = RootContext.TypeManager.LookupType (name);
490                         
491                         if (t != null) {
492
493                                 if (t.IsInterface)
494                                         return t;
495                                 
496                                 string cause;
497                                 
498                                 if (t.IsValueType)
499                                         cause = "is a struct";
500                                 else if (t.IsClass) 
501                                         cause = "is a class";
502                                 else
503                                         cause = "Should not happen.";
504
505                                 Report.Error (527, "`"+name+"' " + cause + ", need an interface instead");
506                                 
507                                 return null;
508                         }
509
510                         Tree tree = RootContext.Tree;
511                         parent = (Interface) tree.Interfaces [name];
512                         if (parent == null){
513                                 string cause = "is undefined";
514                                 
515                                 if (tree.Classes [name] != null)
516                                         cause = "is a class";
517                                 else if (tree.Structs [name] != null)
518                                         cause = "is a struct";
519                                 
520                                 Report.Error (527, "`"+name+"' " + cause + ", need an interface instead");
521                                 return null;
522                         }
523                         
524                         t = parent.DefineInterface (builder);
525                         if (t == null){
526                                 Report.Error (529,
527                                               "Inherited interface `"+name+"' is circular");
528                                 return null;
529                         }
530
531                         return t;
532                 }
533                 
534                 //
535                 // Returns the list of interfaces that this interface implements
536                 // Or null if it does not implement any interface.
537                 //
538                 // Sets the error boolean accoringly.
539                 //
540                 Type [] GetInterfaceBases (object builder, out bool error)
541                 {
542                         Type [] tbases;
543                         int i;
544
545                         error = false;
546                         if (Bases == null)
547                                 return null;
548                         
549                         tbases = new Type [Bases.Count];
550                         i = 0;
551
552                         foreach (string name in Bases){
553                                 Type t;
554                                 
555                                 t = GetInterfaceTypeByName (builder, name);
556                                 if (t == null){
557                                         error = true;
558                                         return null;
559                                 }
560                                 
561                                 tbases [i++] = t;
562                         }
563                         
564                         return tbases;
565                 }
566                 
567                 //
568                 // <summary>
569                 //  Defines the Interface in the appropriate ModuleBuilder or TypeBuilder
570                 // </summary>
571                 // TODO:
572                 //   Rework the way we recurse, because for recursive
573                 //   definitions of interfaces (A:B and B:A) we report the
574                 //   error twice, rather than once.  
575                 
576                 public TypeBuilder DefineInterface (object parent_builder)
577                 {
578                         Type [] ifaces;
579                         bool error;
580
581                         if (InTransit)
582                                 return null;
583                         
584                         InTransit = true;
585                         
586                         ifaces = GetInterfaceBases (parent_builder, out error);
587
588                         if (error)
589                                 return null;
590
591                         if (parent_builder is ModuleBuilder) {
592                                 ModuleBuilder builder = (ModuleBuilder) parent_builder;
593                                 
594                                 TypeBuilder = builder.DefineType (Name,
595                                                                   TypeAttributes.Interface |
596                                                                   InterfaceAttr |
597                                                                   TypeAttributes.Abstract,
598                                                                   null,   // Parent Type
599                                                                   ifaces);
600                         } else {
601                                 TypeBuilder builder = (TypeBuilder) parent_builder;
602
603                                 TypeBuilder = builder.DefineNestedType (Name,
604                                                                         TypeAttributes.Interface |
605                                                                         InterfaceAttr |
606                                                                         TypeAttributes.Abstract,
607                                                                         null,   // Parent Type
608                                                                         ifaces);
609                         }
610                         
611                         RootContext.TypeManager.AddUserInterface (Name, TypeBuilder, this);
612                         
613                         InTransit = false;
614                         
615                         return TypeBuilder;
616                 }
617                 
618                 // <summary>
619                 //   Performs semantic analysis, and then generates the IL interfaces
620                 // </summary>
621                 public void Populate ()
622                 {
623                         if (!SemanticAnalysis ())
624                                 return;
625
626                         if (defined_method != null){
627                                 foreach (InterfaceMethod im in defined_method)
628                                         PopulateMethod (im);
629                         }
630
631                         if (defined_properties != null){
632                                 foreach (InterfaceProperty ip in defined_properties)
633                                         PopulateProperty (ip);
634                         }
635
636                         if (defined_events != null)
637                                 foreach (InterfaceEvent ie in defined_events)
638                                         PopulateEvent (ie);
639
640                         if (defined_indexer != null)
641                                 foreach (InterfaceIndexer ii in defined_indexer)
642                                         PopulateIndexer (ii);
643                 }
644
645                 public void CloseType ()
646                 {
647                         TypeBuilder.CreateType ();
648                 }
649                 
650         }
651
652         public class InterfaceMemberBase {
653                 public readonly string Name;
654                 public readonly bool IsNew;
655                 public Attributes OptAttributes;
656                 
657                 public InterfaceMemberBase (string name, bool is_new, Attributes attrs)
658                 {
659                         Name = name;
660                         IsNew = is_new;
661                         OptAttributes = attrs;
662                 }
663         }
664         
665         public class InterfaceProperty : InterfaceMemberBase {
666                 public readonly bool HasSet;
667                 public readonly bool HasGet;
668                 public readonly string Type;
669                 public readonly string type;
670                 
671                 public InterfaceProperty (string type, string name,
672                                           bool is_new, bool has_get, bool has_set, Attributes attrs)
673                         : base (name, is_new, attrs)
674                 {
675                         Type = type;
676                         HasGet = has_get;
677                         HasSet = has_set;
678                 }
679         }
680
681         public class InterfaceEvent : InterfaceMemberBase {
682                 public readonly string Type;
683                 
684                 public InterfaceEvent (string type, string name, bool is_new, Attributes attrs)
685                         : base (name, is_new, attrs)
686                 {
687                         Type = type;
688                 }
689         }
690         
691         public class InterfaceMethod : InterfaceMemberBase {
692                 public readonly string     ReturnType;
693                 public readonly Parameters Parameters;
694                 
695                 public InterfaceMethod (string return_type, string name, bool is_new, Parameters args, Attributes attrs)
696                         : base (name, is_new, attrs)
697                 {
698                         this.ReturnType = return_type;
699                         this.Parameters = args;
700                 }
701
702                 // <summary>
703                 //   Returns the signature for this interface method
704                 // </summary>
705                 public string GetSignature (TypeContainer tc)
706                 {
707                         Type ret = tc.LookupType (ReturnType, false);
708                         string args = Parameters.GetSignature (tc);
709
710                         if ((ret == null) || (args == null))
711                                 return null;
712                         
713                         return (IsNew ? "new-" : "") + ret.FullName + "(" + args + ")";
714                 }
715
716                 public Type [] ParameterTypes (TypeContainer tc)
717                 {
718                         return Parameters.GetParameterInfo (tc);
719                 }
720         }
721
722         public class InterfaceIndexer : InterfaceMemberBase {
723                 public readonly bool HasGet, HasSet;
724                 public readonly Parameters Parameters;
725                 public readonly string Type;
726                 
727                 public InterfaceIndexer (string type, Parameters args, bool do_get, bool do_set, bool is_new,
728                                          Attributes attrs)
729                         : base ("", is_new, attrs)
730                 {
731                         Type = type;
732                         Parameters = args;
733                         HasGet = do_get;
734                         HasSet = do_set;
735                 }
736
737                 public Type [] ParameterTypes (TypeContainer tc)
738                 {
739                         return Parameters.GetParameterInfo (tc);
740                 }
741         }
742 }