**** Merged from HEAD ****
[mono.git] / mcs / gmcs / 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 #define CACHE
11 using System.Collections;
12 using System;
13 using System.IO;
14 using System.Reflection;
15 using System.Reflection.Emit;
16
17 namespace Mono.CSharp {
18
19         /// <summary>
20         ///   Interfaces
21         /// </summary>
22         public class Interface : DeclSpace, IMemberContainer {
23                 const MethodAttributes interface_method_attributes =
24                         MethodAttributes.Public |
25                         MethodAttributes.Abstract |
26                         MethodAttributes.HideBySig |
27                         MethodAttributes.NewSlot |
28                         MethodAttributes.Virtual;
29
30                 const MethodAttributes property_attributes =
31                         MethodAttributes.Public |
32                         MethodAttributes.Abstract |
33                         MethodAttributes.HideBySig |
34                         MethodAttributes.NewSlot |
35                         MethodAttributes.SpecialName |
36                         MethodAttributes.Virtual;
37                 
38                 ArrayList bases;
39                 
40                 ArrayList defined_method;
41                 ArrayList defined_indexer;
42                 ArrayList defined_events;
43                 ArrayList defined_properties;
44
45                 ArrayList method_builders;
46                 ArrayList property_builders;
47                 ArrayList event_builders;
48                 
49
50                 public string IndexerName;
51
52                 IMemberContainer parent_container;
53                 MemberCache member_cache;
54
55                 bool members_defined;
56
57                 // These will happen after the semantic analysis
58                 
59                 // Hashtable defined_indexers;
60                 // Hashtable defined_methods;
61                 
62                 /// <summary>
63                 ///   Modifiers allowed in a class declaration
64                 /// </summary>
65                 public const int AllowedModifiers =
66                         Modifiers.NEW       |
67                         Modifiers.PUBLIC    |
68                         Modifiers.PROTECTED |
69                         Modifiers.INTERNAL  |
70                         Modifiers.UNSAFE    |
71                         Modifiers.PRIVATE;
72
73                 public Interface (NamespaceEntry ns, TypeContainer parent, string name, int mod,
74                                   Attributes attrs, Location l)
75                         : base (ns, parent, name, attrs, l)
76                 {
77                         ModFlags = Modifiers.Check (AllowedModifiers, mod, Modifiers.PRIVATE, l);
78                         
79                         method_builders = new ArrayList ();
80                         property_builders = new ArrayList ();
81                         event_builders = new ArrayList ();
82                 }
83
84                 public AdditionResult AddMethod (InterfaceMethod imethod)
85                 {
86                         string name = imethod.Name;
87                         Object value = defined_names [name];
88
89                         if (value != null){
90                                 if (!(value is InterfaceMethod))
91                                         return AdditionResult.NameExists;
92                         } 
93
94                         if (defined_method == null)
95                                 defined_method = new ArrayList ();
96
97                         defined_method.Add (imethod);
98                         if (value == null)
99                                 DefineName (name, imethod);
100                         
101                         return AdditionResult.Success;
102                 }
103
104                 public AdditionResult AddProperty (InterfaceProperty iprop)
105                 {
106                         AdditionResult res;
107                         string name = iprop.Name;
108
109                         if ((res = IsValid (name, name)) != AdditionResult.Success)
110                                 return res;
111
112                         DefineName (name, iprop);
113
114                         if (defined_properties == null)
115                                 defined_properties = new ArrayList ();
116
117                         defined_properties.Add (iprop);
118                         return AdditionResult.Success;
119                 }
120
121                 public AdditionResult AddEvent (InterfaceEvent ievent)
122                 {
123                         string name = ievent.Name;
124                         AdditionResult res;
125                         
126                         if ((res = IsValid (name, name)) != AdditionResult.Success)
127                                 return res;
128
129                         DefineName (name, ievent);
130
131                         if (defined_events == null)
132                                 defined_events = new ArrayList ();
133
134                         defined_events.Add (ievent);
135                         return AdditionResult.Success;
136                 }
137
138                 public bool AddIndexer (InterfaceIndexer iindexer)
139                 {
140                         if (defined_indexer == null)
141                                 defined_indexer = new ArrayList ();
142                         
143                         defined_indexer.Add (iindexer);
144                         return true;
145                 }
146                 
147                 public ArrayList InterfaceMethods {
148                         get {
149                                 return defined_method;
150                         }
151                 }
152
153                 public ArrayList InterfaceProperties {
154                         get {
155                                 return defined_properties;
156                         }
157                 }
158
159                 public ArrayList InterfaceEvents {
160                         get {
161                                 return defined_events;
162                         }
163                 }
164
165                 public ArrayList InterfaceIndexers {
166                         get {
167                                 return defined_indexer;
168                         }
169                 }
170
171                 public ArrayList Bases {
172                         get {
173                                 return bases;
174                         }
175
176                         set {
177                                 bases = value;
178                         }
179                 }
180
181                 public virtual TypeAttributes InterfaceAttr {
182                         get {
183                                 TypeAttributes x = TypeAttributes.Interface | TypeAttributes.Abstract;
184
185                                 if (IsTopLevel == false) {
186                                         
187                                         if ((ModFlags & Modifiers.PROTECTED) != 0
188                                             && (ModFlags & Modifiers.INTERNAL) != 0)
189                                                 x |= TypeAttributes.NestedFamORAssem;
190                                         else if ((ModFlags & Modifiers.PROTECTED) != 0)
191                                                 x |= TypeAttributes.NestedFamily;
192                                         else if ((ModFlags & Modifiers.INTERNAL) != 0)
193                                                 x |= TypeAttributes.NestedAssembly;
194                                         else if ((ModFlags & Modifiers.PUBLIC) != 0)
195                                                 x |= TypeAttributes.NestedPublic;
196                                         else
197                                                 x |= TypeAttributes.NestedPrivate;
198                                 } else {
199                                         if ((ModFlags & Modifiers.PUBLIC) != 0)
200                                                 x |= TypeAttributes.Public;
201                                         else if ((ModFlags & Modifiers.PRIVATE) != 0)
202                                                 x |= TypeAttributes.NotPublic;
203                                 }
204                                 
205                                 if ((ModFlags & Modifiers.ABSTRACT) != 0)
206                                         x |= TypeAttributes.Abstract;
207                                 
208                                 if ((ModFlags & Modifiers.SEALED) != 0)
209                                         x |= TypeAttributes.Sealed;
210
211                                 return x;
212                         }
213                 }
214                 
215                 void Error111 (InterfaceMemberBase ib)
216                 {
217                         Report.Error (
218                                 111,
219                                 "Interface `" + Name + "' already contains a definition with the " +
220                                 "same return value and parameter types for member `" + ib.Name + "'");
221                 }
222
223                 bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] types)
224                 {
225                         if (!TypeManager.RegisterMethod (mb, ip, types))
226                                 return false;
227
228                         method_builders.Add (mb);
229                         return true;
230                 }
231
232                 //
233                 // This might trigger a definition of the methods.  This happens only
234                 // with Attributes, as Attribute classes are processed before interfaces.
235                 // Ideally, we should make everything just define recursively in terms
236                 // of its dependencies.
237                 //
238                 public MethodInfo [] GetMethods (TypeContainer container)
239                 {
240                         int n = 0;
241                         
242                         if (!members_defined){
243                                 if (DefineMembers (container))
244                                         n = method_builders.Count;
245                         } else
246                                 n = method_builders.Count;
247                         
248                         MethodInfo [] mi = new MethodInfo [n];
249                         
250                         method_builders.CopyTo (mi, 0);
251
252                         return mi;
253                 }
254
255                 // Hack around System.Reflection as found everywhere else
256                 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
257                                                         MemberFilter filter, object criteria)
258                 {
259                         ArrayList members = new ArrayList ();
260
261                         if ((mt & MemberTypes.Method) != 0) {
262                                 foreach (MethodBuilder mb in method_builders)
263                                         if (filter (mb, criteria))
264                                                 members.Add (mb);
265                         }
266
267                         if ((mt & MemberTypes.Property) != 0) {
268                                 foreach (PropertyBuilder pb in property_builders)
269                                         if (filter (pb, criteria))
270                                                 members.Add (pb);
271                         }
272
273                         if ((mt & MemberTypes.Event) != 0) {
274                                 foreach (MyEventBuilder eb in event_builders)
275                                         if (filter (eb, criteria))
276                                                 members.Add (eb);
277                         }
278
279                         if (((bf & BindingFlags.DeclaredOnly) == 0) && (TypeBuilder.BaseType != null)) {
280                                 MemberList parent_mi;
281                                 
282                                 parent_mi = TypeContainer.FindMembers (
283                                         TypeBuilder.BaseType, mt, bf, filter, criteria);
284
285                                 members.AddRange (parent_mi);
286                         }
287
288                         return new MemberList (members);
289                 }
290
291                 public override MemberCache MemberCache {
292                         get {
293                                 return member_cache;
294                         }
295                 }
296
297                 //
298                 // Populates the methods in the interface
299                 //
300                 void PopulateMethod (TypeContainer parent, DeclSpace decl_space, InterfaceMethod im)
301                 {
302                         Type return_type = im.ReturnType.Type;
303                         if (return_type == null)
304                                 return_type = this.ResolveType (im.ReturnType, false, im.Location);
305                         
306                         Type [] arg_types = im.ParameterTypes (this);
307                         MethodBuilder mb;
308
309                         if (return_type == null)
310                                 return;
311
312                         if (return_type.IsPointer && !UnsafeOK (this))
313                                 return;
314
315                         if (arg_types == null)
316                                 return;
317
318                         foreach (Type t in arg_types){
319
320                                 if (t == null)
321                                         return;
322                                 
323                                 if (t.IsPointer && !UnsafeOK (this))
324                                         return;
325                         }
326                         
327                         //
328                         // Create the method
329                         //
330                         mb = TypeBuilder.DefineMethod (
331                                 im.Name, interface_method_attributes,
332                                 return_type, arg_types);
333
334                         InternalParameters ip = new InternalParameters (arg_types, im.Parameters);
335
336                         if (!RegisterMethod (mb, ip, arg_types)) {
337                                 Error111 (im);
338                                 return;
339                         }
340
341                         //
342                         // Labelling of parameters is taken care of
343                         // during the Emit phase via
344                         // MethodCore.LabelParameters method so I am
345                         // removing the old code here.
346                         //
347                         
348                         im.Builder = mb;
349                         
350                 }
351
352                 //
353                 // Populates the properties in the interface
354                 //
355                 void PopulateProperty (TypeContainer parent, DeclSpace decl_space, InterfaceProperty ip)
356                 {
357                         PropertyBuilder pb;
358                         MethodBuilder get = null, set = null;
359                         ip.Type = this.ResolveTypeExpr (ip.Type, false, ip.Location);
360                         if (ip.Type == null)
361                                 return;
362                         
363                         Type prop_type = ip.Type.Type;
364                         Type [] setter_args = new Type [1];
365
366                         if (prop_type == null)
367                                 return;
368
369                         if (prop_type.IsPointer && !UnsafeOK (this))
370                                 return;
371                         
372                         setter_args [0] = prop_type;
373
374                         //
375                         // FIXME: properties are missing the following
376                         // flags: hidebysig newslot specialname
377                         //
378                         pb = TypeBuilder.DefineProperty (
379                                 ip.Name, PropertyAttributes.None,
380                                 prop_type, null);
381
382                         if (ip.HasGet){
383                                 get = TypeBuilder.DefineMethod (
384                                         "get_" + ip.Name, property_attributes ,
385                                         prop_type, null);
386
387                                 //
388                                 // HACK because System.Reflection.Emit is lame
389                                 //
390                                 Type [] null_types = null;
391                                 InternalParameters inp = new InternalParameters
392                                         (null_types, Parameters.EmptyReadOnlyParameters);
393                                 
394                                 if (!RegisterMethod (get, inp, null)) {
395                                         Error111 (ip);
396                                         return;
397                                 }
398                                 
399                                 pb.SetGetMethod (get);
400                         }
401
402                         if (ip.HasSet){
403                                 setter_args [0] = prop_type;
404
405                                 set = TypeBuilder.DefineMethod (
406                                         "set_" + ip.Name, property_attributes,
407                                         TypeManager.void_type, setter_args);
408
409                                 set.DefineParameter (1, ParameterAttributes.None, "value");
410                                 pb.SetSetMethod (set);
411
412                                 //
413                                 // HACK because System.Reflection.Emit is lame
414                                 //
415                                 Parameter [] parms = new Parameter [1];
416                                 parms [0] = new Parameter (ip.Type, "value", Parameter.Modifier.NONE, null);
417                                 InternalParameters ipp = new InternalParameters (
418                                         this, new Parameters (parms, null, Location.Null));
419                                         
420                                 if (!RegisterMethod (set, ipp, setter_args)) {
421                                         Error111 (ip);
422                                         return;
423                                 }
424                         }
425
426                         TypeManager.RegisterProperty (pb, get, set);
427                         property_builders.Add (pb);
428                         ip.Builder = pb;
429                 }
430
431                 //
432                 // Populates the events in the interface
433                 //
434                 void PopulateEvent (TypeContainer parent, DeclSpace decl_space, InterfaceEvent ie)
435                 {
436                         //
437                         // FIXME: We need to do this after delegates have been
438                         // declared or we declare them recursively.
439                         //
440                         MyEventBuilder eb;
441                         MethodBuilder add = null, remove = null;
442                         ie.Type = this.ResolveTypeExpr (ie.Type, false, ie.Location);
443                         if (ie.Type == null)
444                                 return;
445                         
446                         Type event_type = ie.Type.Type;
447
448                         if (event_type == null)
449                                 return;
450
451                         if (event_type.IsPointer && !UnsafeOK (this))
452                                 return;
453
454                         Type [] parameters = new Type [1];
455                         parameters [0] = event_type;
456
457                         eb = new MyEventBuilder (null, TypeBuilder, ie.Name,
458                                                  EventAttributes.None, event_type);
459
460                         //
461                         // Now define the accessors
462                         //
463                         string add_name = "add_" + ie.Name;
464                         
465                         add = TypeBuilder.DefineMethod (
466                                 add_name, property_attributes, null, parameters);
467                         add.DefineParameter (1, ParameterAttributes.None, "value");
468                         eb.SetAddOnMethod (add);
469
470                         string remove_name = "remove_" + ie.Name;
471                         remove = TypeBuilder.DefineMethod (
472                                 remove_name, property_attributes, null, parameters);
473                         remove.DefineParameter (1, ParameterAttributes.None, "value");
474                         eb.SetRemoveOnMethod (remove);
475
476                         Parameter [] parms = new Parameter [1];
477                         parms [0] = new Parameter (ie.Type, "value", Parameter.Modifier.NONE, null);
478                         InternalParameters ip = new InternalParameters (
479                                 this, new Parameters (parms, null, Location.Null));
480
481                         if (!RegisterMethod (add, ip, parameters)) {
482                                 Error111 (ie);
483                                 return;
484                         }
485                         
486                         if (!RegisterMethod (remove, ip, parameters)) {
487                                 Error111 (ie);
488                                 return;
489                         }
490
491                         TypeManager.RegisterEvent (eb, add, remove);
492                         event_builders.Add (eb);
493
494                         ie.Builder = eb;
495                 }
496
497                 //
498                 // Populates the indexers in the interface
499                 //
500                 void PopulateIndexer (TypeContainer parent, DeclSpace decl_space, InterfaceIndexer ii)
501                 {
502                         PropertyBuilder pb;
503                         ii.Type = this.ResolveTypeExpr (ii.Type, false, ii.Location);
504                         if (ii.Type == null)
505                                 return;
506                         
507                         Type prop_type = ii.Type.Type;
508                         Type [] arg_types = ii.ParameterTypes (this);
509                         Type [] value_arg_types;
510
511                         if (prop_type == null)
512                                 return;
513
514                         if (prop_type.IsPointer && !UnsafeOK (this))
515                                 return;
516                         
517                         //
518                         // Sets up the extra invisible `value' argument for setters.
519                         // 
520                         if (arg_types != null){
521                                 int count = arg_types.Length;
522                                 value_arg_types = new Type [count + 1];
523
524                                 arg_types.CopyTo (value_arg_types, 0);
525                                 value_arg_types [count] = prop_type;
526
527                                 foreach (Type t in arg_types){
528                                         if (t.IsPointer && !UnsafeOK (this))
529                                                 return;
530                                 }
531                         } else {
532                                 value_arg_types = new Type [1];
533
534                                 value_arg_types [1] = prop_type;
535                         }
536
537                         EmitContext ec = new EmitContext (parent, decl_space, Location, null,
538                                                           null, ModFlags, false);
539
540                         IndexerName = Attribute.ScanForIndexerName (ec, ii.OptAttributes);
541                         if (IndexerName == null)
542                                 IndexerName = "Item";
543                         
544                         pb = TypeBuilder.DefineProperty (
545                                 IndexerName, PropertyAttributes.None,
546                                 prop_type, arg_types);
547                         
548                         MethodBuilder set_item = null, get_item = null;
549                         if (ii.HasGet){
550                                 Parameter [] p = ii.Parameters.FixedParameters;
551                                 
552                                 get_item = TypeBuilder.DefineMethod (
553                                         "get_" + IndexerName, property_attributes,
554                                         prop_type, arg_types);
555                                 pb.SetGetMethod (get_item);
556                                 //
557                                 // HACK because System.Reflection.Emit is lame
558                                 //
559                                 InternalParameters ip = new InternalParameters (
560                                         arg_types, ii.Parameters);
561                                 
562                                 if (!RegisterMethod (get_item, ip, arg_types)) {
563                                         Error111 (ii);
564                                         return;
565                                 }
566
567                                 if (p != null){
568                                         for (int i = 0; i < p.Length; i++)
569                                                 get_item.DefineParameter (
570                                                         i + 1,
571                                                         p [i].Attributes, p [i].Name);
572                                 }
573                         }
574
575                         if (ii.HasSet){
576                                 Parameter [] p = ii.Parameters.FixedParameters;
577                                 Parameter [] pv;
578                                 int i = 0;
579                                 
580                                 pv = new Parameter [p.Length + 1];
581                                 p.CopyTo (pv, 0);
582                                 pv [p.Length] = new Parameter (ii.Type, "value", Parameter.Modifier.NONE, null);
583                                 Parameters value_params = new Parameters (pv, null, Location.Null);
584                                 value_params.GetParameterInfo (decl_space);
585                                 
586                                 set_item = TypeBuilder.DefineMethod (
587                                         "set_" + IndexerName, property_attributes,
588                                         TypeManager.void_type, value_arg_types);
589                                 pb.SetSetMethod (set_item);
590                                 //
591                                 // HACK because System.Reflection.Emit is lame
592                                 //
593                                 InternalParameters ip = new InternalParameters (
594                                         value_arg_types, value_params);
595                                 if (!RegisterMethod (set_item, ip, value_arg_types)) {
596                                         Error111 (ii);
597                                         return;
598                                 }
599
600                                 if (p != null){
601                                         for (; i < p.Length; i++)
602                                                 set_item.DefineParameter (
603                                                         i + 1,
604                                                         p [i].Attributes, p [i].Name);
605                                 }
606                                 
607                                 set_item.DefineParameter (i + 1, ParameterAttributes.None, "value");
608                         }
609
610                         property_builders.Add (pb);
611
612                         ii.Builder = pb;
613                 }
614
615                 /// <summary>
616                 ///   Performs the semantic analysis for all the interface members
617                 ///   that were declared
618                 /// </summary>
619                 bool SemanticAnalysis ()
620                 {
621                         Hashtable methods = new Hashtable ();
622
623                         
624                         if (defined_method != null){
625                                 foreach (InterfaceMethod im in defined_method){
626                                         string sig = im.GetSignature (this);
627                                         
628                                         //
629                                         // If there was an undefined Type on the signatures
630                                         // 
631                                         if (sig == null)
632                                                 continue;
633                                         
634                                         if (methods [sig] != null){
635                                                 Error111 (im);
636                                                 return false;
637                                         }
638                                 }
639                         }
640
641                         //
642                         // FIXME: Here I should check i
643                         // 
644                         return true;
645                 }
646
647                 TypeExpr GetInterfaceTypeByName (Expression name)
648                 {
649                         TypeExpr resolved = ResolveTypeExpr (name, false, Location);
650                         if (resolved == null)
651                                 return null;
652
653                         if (resolved.IsInterface)
654                                 return resolved;
655                                 
656                         string cause;
657                         
658                         if (resolved.IsValueType)
659                                 cause = "is a struct";
660                         else if (resolved.IsClass) 
661                                 cause = "is a class";
662                         else
663                                 cause = "Should not happen.";
664                         
665                         Report.Error (527, Location, "`"+resolved.Name+"' " + cause +
666                                       ", need an interface instead");
667                         
668                         return null;
669                 }
670                 
671                 //
672                 // Returns the list of interfaces that this interface implements
673                 // Or null if it does not implement any interface.
674                 //
675                 // Sets the error boolean accoringly.
676                 //
677                 TypeExpr [] GetInterfaceBases (out bool error)
678                 {
679                         TypeExpr [] tbases;
680                         int i;
681
682                         error = false;
683                         if (Bases == null)
684                                 return null;
685                         
686                         tbases = new TypeExpr [Bases.Count];
687                         i = 0;
688
689                         foreach (Expression name in Bases){
690                                 TypeExpr t;
691
692                                 t = GetInterfaceTypeByName (name);
693                                 if (t == null){
694                                         error = true;
695                                         return null;
696                                 }
697
698                                 if (!t.AsAccessible (Parent, ModFlags))
699                                         Report.Error (61, Location,
700                                                       "Inconsistent accessibility: base interface `" +
701                                                       t.Name + "' is less accessible than interface `" +
702                                                       Name + "'");
703
704                                 tbases [i++] = t;
705                         }
706                         
707                         return TypeManager.ExpandInterfaces (tbases);
708                 }
709                 
710                 //
711                 // <summary>
712                 //  Defines the Interface in the appropriate ModuleBuilder or TypeBuilder
713                 // </summary>
714                 //
715                 // TODO:
716                 //   Rework the way we recurse, because for recursive
717                 //   definitions of interfaces (A:B and B:A) we report the
718                 //   error twice, rather than once.  
719                 
720                 public override TypeBuilder DefineType ()
721                 {
722                         TypeExpr [] ifaces;
723                         bool error;
724
725                         if (TypeBuilder != null)
726                                 return TypeBuilder;
727                         
728                         if (InTransit)
729                                 return null;
730                         
731                         InTransit = true;
732                         
733                         EmitContext ec = new EmitContext (this, this, Location, null, null,
734                                                           ModFlags, false);
735
736                         ifaces = GetInterfaceBases (out error);
737
738                         if (error)
739                                 return null;
740
741                         if (IsGeneric) {
742                                 foreach (TypeParameter type_param in TypeParameters)
743                                         if (!type_param.Resolve (this)) {
744                                                 error = true;
745                                                 return null;
746                                         }
747                         }
748                         
749                         if (IsTopLevel) {
750                                 if (TypeManager.NamespaceClash (Name, Location))
751                                         return null;
752                                 
753                                 ModuleBuilder builder = CodeGen.ModuleBuilder;
754
755                                 TypeBuilder = builder.DefineType (
756                                         Name,
757                                         InterfaceAttr,
758                                         (Type)null,   // Parent Type
759                                         null);
760                                 RootContext.RegisterOrder (this);
761                         } else {
762                                 TypeBuilder builder = Parent.TypeBuilder;
763
764                                 TypeBuilder = builder.DefineNestedType (
765                                         Basename,
766                                         InterfaceAttr,
767                                         (Type) null, //parent type
768                                         null);
769
770                                 TypeContainer tc = TypeManager.LookupTypeContainer (builder);
771                                 tc.RegisterOrder (this);
772                         }
773
774                         if (IsGeneric) {
775                                 foreach (TypeParameter type_param in TypeParameters)
776                                         type_param.Define (TypeBuilder);
777
778                                 foreach (TypeParameter type_param in TypeParameters)
779                                         type_param.DefineType (ec, TypeBuilder);
780                         }
781
782                         if (ifaces != null) {
783                                 foreach (TypeExpr iface in ifaces) {
784                                         Type itype = iface.ResolveType (ec);
785                                         TypeBuilder.AddInterfaceImplementation (itype);
786                                 }
787                         }
788
789                         TypeManager.AddUserInterface (Name, TypeBuilder, this, ifaces);
790                         InTransit = false;
791
792                         return TypeBuilder;
793                 }
794
795                 //
796                 // Defines the indexers, and also verifies that the IndexerNameAttribute in the
797                 // interface is consistent.  Either it is `Item' or it is the name defined by all the
798                 // indexers with the `IndexerName' attribute.
799                 //
800                 // Turns out that the IndexerNameAttribute is applied to each indexer,
801                 // but it is never emitted, instead a DefaultName attribute is attached
802                 // to the interface
803                 //
804                 void DefineIndexers (TypeContainer parent)
805                 {
806                         string interface_indexer_name = null;
807
808                         foreach (InterfaceIndexer ii in defined_indexer){
809
810                                 PopulateIndexer (parent, this, ii);
811
812                                 if (interface_indexer_name == null){
813                                         interface_indexer_name = IndexerName;
814                                         continue;
815                                 }
816                                 
817                                 if (IndexerName == interface_indexer_name)
818                                         continue;
819                                 
820                                 Report.Error (
821                                         668, "Two indexers have different names, " +
822                                         " you should use the same name for all your indexers");
823                         }
824                         if (interface_indexer_name == null)
825                                 interface_indexer_name = "Item";
826                         IndexerName = interface_indexer_name;
827                 }
828                 
829                 /// <summary>
830                 ///   Performs semantic analysis, and then generates the IL interfaces
831                 /// </summary>
832                 public override bool DefineMembers (TypeContainer parent)
833                 {
834                         if (members_defined)
835                                 return true;
836                         
837                         if (!SemanticAnalysis ())
838                                 return false;
839
840                         
841                         if (defined_method != null){
842                                 foreach (InterfaceMethod im in defined_method)
843                                         PopulateMethod (parent, this, im);
844                         }
845
846                         if (defined_properties != null){
847                                 foreach (InterfaceProperty ip in defined_properties)
848                                         PopulateProperty (parent, this, ip);
849                         }
850
851                         if (defined_events != null)
852                                 foreach (InterfaceEvent ie in defined_events)
853                                         PopulateEvent (parent, this, ie);
854
855                         if (defined_indexer != null) {
856                                 DefineIndexers (parent);
857
858                                 CustomAttributeBuilder cb = EmitDefaultMemberAttr (
859                                         parent, IndexerName, ModFlags, Location);
860                                 if (cb != null)
861                                         TypeBuilder.SetCustomAttribute (cb);
862                         }
863
864 #if CACHE
865                         if (TypeBuilder.BaseType != null)
866                                 parent_container = TypeManager.LookupMemberContainer (TypeBuilder.BaseType);
867
868                         member_cache = new MemberCache (this);
869 #endif
870                         members_defined = true;
871                         return true;
872                 }
873
874
875                 //
876                 // In the case of Interfaces, there is nothing to do here
877                 //
878                 public override bool Define (TypeContainer parent)
879                 {
880                         return true;
881                 }
882
883                 /// <summary>
884                 ///   Applies all the attributes.
885                 /// </summary>
886                 public void Emit (TypeContainer tc)
887                 {
888                         if (OptAttributes != null) {
889                                 EmitContext ec = new EmitContext (tc, this, Location, null, null,
890                                                                   ModFlags, false);
891                                 Attribute.ApplyAttributes (ec, TypeBuilder, this, OptAttributes);
892                         }
893
894                         // Now emit attributes for each interface member
895                         if (defined_method != null) {
896                                 foreach (InterfaceMethod im in defined_method) {
897                                         EmitContext ec = new EmitContext (tc, this, Location, null,
898                                                                           im.ReturnType.Type, ModFlags, false);
899   
900                                         MethodCore.LabelParameters (ec, im.Builder,
901                                                                     im.Parameters,
902                                                                     im.OptAttributes,
903                                                                     Location);
904                                         
905                                         if (im.OptAttributes != null)
906                                                 Attribute.ApplyAttributes (ec, im.Builder,
907                                                                            im, im.OptAttributes);
908                                         
909                                 }
910                         }
911
912                         if (defined_properties != null) {
913                                 foreach (InterfaceProperty ip in defined_properties) {
914                                         EmitContext ec = new EmitContext (tc, this, Location, null,
915                                                                           null, ModFlags, false);
916                                         
917                                         if (ip.OptAttributes != null)
918                                                 Attribute.ApplyAttributes (ec, ip.Builder, ip, ip.OptAttributes);
919                                 }
920                         }
921
922                         if (defined_events != null) {
923                                 foreach (InterfaceEvent ie in defined_events) {
924                                         EmitContext ec = new EmitContext (tc, this, Location, null,
925                                                                           null, ModFlags, false);
926                                         
927                                         if (ie.OptAttributes != null)
928                                                 Attribute.ApplyAttributes (ec, ie.Builder, ie, ie.OptAttributes);
929                                 }
930                         }
931                 }
932
933                 public static CustomAttributeBuilder EmitDefaultMemberAttr (TypeContainer parent,
934                                                                             string name,
935                                                                             int flags,
936                                                                             Location loc)
937                 {
938                         EmitContext ec = new EmitContext (parent, loc, null, null, flags);
939
940                         Expression ml = Expression.MemberLookup (ec, TypeManager.default_member_type,
941                                                                  ".ctor", MemberTypes.Constructor,
942                                                                  BindingFlags.Public | BindingFlags.Instance,
943                                                                  Location.Null);
944                         
945                         if (!(ml is MethodGroupExpr)) {
946                                 Console.WriteLine ("Internal error !!!!");
947                                 return null;
948                         }
949                         
950                         MethodGroupExpr mg = (MethodGroupExpr) ml;
951
952                         MethodBase constructor = mg.Methods [0];
953
954                         string [] vals = { name };
955
956                         CustomAttributeBuilder cb = null;
957                         try {
958                                 cb = new CustomAttributeBuilder ((ConstructorInfo) constructor, vals);
959                         } catch {
960                                 Report.Warning (-100, "Can not set the indexer default member attribute");
961                         }
962
963                         return cb;
964                 }
965
966                 //
967                 // IMemberContainer
968                 //
969
970                 string IMemberContainer.Name {
971                         get {
972                                 return Name;
973                         }
974                 }
975
976                 Type IMemberContainer.Type {
977                         get {
978                                 return TypeBuilder;
979                         }
980                 }
981
982                 IMemberContainer IMemberContainer.Parent {
983                         get {
984                                 return parent_container;
985                         }
986                 }
987
988                 MemberCache IMemberContainer.MemberCache {
989                         get {
990                                 return member_cache;
991                         }
992                 }
993
994                 bool IMemberContainer.IsInterface {
995                         get {
996                                 return true;
997                         }
998                 }
999
1000                 MemberList IMemberContainer.GetMembers (MemberTypes mt, BindingFlags bf)
1001                 {
1002                         // Interfaces only contain instance members.
1003                         if ((bf & BindingFlags.Instance) == 0)
1004                                 return MemberList.Empty;
1005                         if ((bf & BindingFlags.Public) == 0)
1006                                 return MemberList.Empty;
1007
1008                         ArrayList members = new ArrayList ();
1009
1010                         if ((mt & MemberTypes.Method) != 0)
1011                                 members.AddRange (method_builders);
1012
1013                         if ((mt & MemberTypes.Property) != 0)
1014                                 members.AddRange (property_builders);
1015
1016                         if ((mt & MemberTypes.Event) != 0)
1017                                 members.AddRange (event_builders);
1018
1019                         return new MemberList (members);
1020                 }
1021         }
1022
1023         public class InterfaceMemberBase {
1024                 public readonly string Name;
1025                 public readonly bool IsNew;
1026                 public Attributes OptAttributes;
1027                 
1028                 public InterfaceMemberBase (string name, bool is_new, Attributes attrs)
1029                 {
1030                         Name = name;
1031                         IsNew = is_new;
1032                         OptAttributes = attrs;
1033                 }
1034         }
1035         
1036         public class InterfaceProperty : InterfaceMemberBase {
1037                 public readonly bool HasSet;
1038                 public readonly bool HasGet;
1039                 public readonly Location Location;
1040                 public Expression Type;
1041                 public PropertyBuilder Builder;
1042                 
1043                 public InterfaceProperty (Expression type, string name,
1044                                           bool is_new, bool has_get, bool has_set,
1045                                           Attributes attrs, Location loc)
1046                         : base (name, is_new, attrs)
1047                 {
1048                         Type = type;
1049                         HasGet = has_get;
1050                         HasSet = has_set;
1051                         Location = loc;
1052                 }
1053         }
1054
1055         public class InterfaceEvent : InterfaceMemberBase {
1056                 public readonly Location Location;
1057                 public Expression Type;
1058                 public MyEventBuilder Builder;
1059                 
1060                 public InterfaceEvent (Expression type, string name, bool is_new, Attributes attrs,
1061                                        Location loc)
1062                         : base (name, is_new, attrs)
1063                 {
1064                         Type = type;
1065                         Location = loc;
1066                 }
1067         }
1068         
1069         public class InterfaceMethod : InterfaceMemberBase {
1070                 public Expression ReturnType;
1071                 public readonly Parameters Parameters;
1072                 public readonly Location Location;
1073                 public MethodBuilder Builder;
1074                 
1075                 public InterfaceMethod (Expression return_type, string name, bool is_new, Parameters args,
1076                                         Attributes attrs, Location l)
1077                         : base (name, is_new, attrs)
1078                 {
1079                         this.ReturnType = return_type;
1080                         this.Parameters = args;
1081                         Location = l;
1082                 }
1083
1084                 /// <summary>
1085                 ///   Returns the signature for this interface method
1086                 /// </summary>
1087                 public string GetSignature (DeclSpace ds)
1088                 {
1089                         ReturnType = ds.ResolveTypeExpr (ReturnType, false, Location);
1090                         if (ReturnType == null)
1091                                 return null;
1092                         
1093                         Type ret = ReturnType.Type;
1094                         string args = Parameters.GetSignature (ds);
1095
1096                         if ((ret == null) || (args == null))
1097                                 return null;
1098                         
1099                         return (IsNew ? "new-" : "") + ret.FullName + "(" + args + ")";
1100                 }
1101
1102                 public Type [] ParameterTypes (DeclSpace ds)
1103                 {
1104                         return Parameters.GetParameterInfo (ds);
1105                 }
1106         }
1107
1108         public class InterfaceIndexer : InterfaceMemberBase {
1109                 public readonly bool HasGet, HasSet;
1110                 public readonly Parameters Parameters;
1111                 public readonly Location Location;
1112                 public Expression Type;
1113                 public PropertyBuilder Builder;
1114                 
1115                 public InterfaceIndexer (Expression type, Parameters args, bool do_get, bool do_set,
1116                                          bool is_new, Attributes attrs, Location loc)
1117                         : base ("", is_new, attrs)
1118                 {
1119                         Type = type;
1120                         Parameters = args;
1121                         HasGet = do_get;
1122                         HasSet = do_set;
1123                         Location = loc;
1124                 }
1125
1126                 public Type [] ParameterTypes (DeclSpace ds)
1127                 {
1128                         return Parameters.GetParameterInfo (ds);
1129                 }
1130         }
1131 }