2008-02-16 Ivan N. Zlatev <contact@i-nz.net>
[mono.git] / mcs / mcs / delegate.cs
1 //
2 // delegate.cs: Delegate Handler
3 //
4 // Authors:
5 //     Ravi Pratap (ravi@ximian.com)
6 //     Miguel de Icaza (miguel@ximian.com)
7 //     Marek Safar (marek.safar@gmail.com)
8 //
9 // Licensed under the terms of the GNU GPL
10 //
11 // (C) 2001 Ximian, Inc (http://www.ximian.com)
12 //
13 //
14
15 using System;
16 using System.Collections;
17 using System.Reflection;
18 using System.Reflection.Emit;
19 using System.Text;
20
21 namespace Mono.CSharp {
22
23         /// <summary>
24         ///   Holds Delegates
25         /// </summary>
26         public class Delegate : DeclSpace, IMemberContainer
27         {
28                 public Expression ReturnType;
29                 public Parameters      Parameters;
30
31                 public ConstructorBuilder ConstructorBuilder;
32                 public MethodBuilder      InvokeBuilder;
33                 public MethodBuilder      BeginInvokeBuilder;
34                 public MethodBuilder      EndInvokeBuilder;
35                 
36                 Type ret_type;
37
38                 static string[] attribute_targets = new string [] { "type", "return" };
39                 
40                 Expression instance_expr;
41                 MethodBase delegate_method;
42                 ReturnParameter return_attributes;
43
44                 MemberCache member_cache;
45         
46                 const int AllowedModifiers =
47                         Modifiers.NEW |
48                         Modifiers.PUBLIC |
49                         Modifiers.PROTECTED |
50                         Modifiers.INTERNAL |
51                         Modifiers.UNSAFE |
52                         Modifiers.PRIVATE;
53
54                 public Delegate (NamespaceEntry ns, DeclSpace parent, Expression type,
55                                  int mod_flags, MemberName name, Parameters param_list,
56                                  Attributes attrs)
57                         : base (ns, parent, name, attrs)
58
59                 {
60                         this.ReturnType = type;
61                         ModFlags        = Modifiers.Check (AllowedModifiers, mod_flags,
62                                                            IsTopLevel ? Modifiers.INTERNAL :
63                                                            Modifiers.PRIVATE, name.Location);
64                         Parameters      = param_list;
65                 }
66
67                 public override void ApplyAttributeBuilder(Attribute a, CustomAttributeBuilder cb)
68                 {
69                         if (a.Target == AttributeTargets.ReturnValue) {
70                                 if (return_attributes == null)
71                                         return_attributes = new ReturnParameter (InvokeBuilder, Location);
72
73                                 return_attributes.ApplyAttributeBuilder (a, cb);
74                                 return;
75                         }
76
77                         base.ApplyAttributeBuilder (a, cb);
78                 }
79
80                 public override TypeBuilder DefineType ()
81                 {
82                         if (TypeBuilder != null)
83                                 return TypeBuilder;
84
85                         if (TypeManager.multicast_delegate_type == null && !RootContext.StdLib) {
86                                 Namespace system = RootNamespace.Global.GetNamespace ("System", true);
87                                 TypeExpr expr = system.Lookup (this, "MulticastDelegate", Location) as TypeExpr;
88                                 TypeManager.multicast_delegate_type = expr.Type;
89                         }
90
91                         if (TypeManager.multicast_delegate_type == null)
92                                 Report.Error (-100, Location, "Internal error: delegate used before " +
93                                               "System.MulticastDelegate is resolved.  This can only " +
94                                               "happen during corlib compilation, when using a delegate " +
95                                               "in any of the `core' classes.  See bug #72015 for details.");
96
97                         if (IsTopLevel) {
98                                 if (TypeManager.NamespaceClash (Name, Location))
99                                         return null;
100                                 
101                                 ModuleBuilder builder = CodeGen.Module.Builder;
102
103                                 TypeBuilder = builder.DefineType (
104                                         Name, TypeAttr, TypeManager.multicast_delegate_type);
105                         } else {
106                                 TypeBuilder builder = Parent.TypeBuilder;
107
108                                 string name = Name.Substring (1 + Name.LastIndexOf ('.'));
109                                 TypeBuilder = builder.DefineNestedType (
110                                         name, TypeAttr, TypeManager.multicast_delegate_type);
111                         }
112
113                         TypeManager.AddUserType (this);
114
115 #if GMCS_SOURCE
116                         if (IsGeneric) {
117                                 string[] param_names = new string [TypeParameters.Length];
118                                 for (int i = 0; i < TypeParameters.Length; i++)
119                                         param_names [i] = TypeParameters [i].Name;
120
121                                 GenericTypeParameterBuilder[] gen_params;
122                                 gen_params = TypeBuilder.DefineGenericParameters (param_names);
123
124                                 int offset = CountTypeParameters - CurrentTypeParameters.Length;
125                                 for (int i = offset; i < gen_params.Length; i++)
126                                         CurrentTypeParameters [i - offset].Define (gen_params [i]);
127
128                                 foreach (TypeParameter type_param in CurrentTypeParameters) {
129                                         if (!type_param.Resolve (this))
130                                                 return null;
131                                 }
132
133                                 Expression current = new SimpleName (
134                                         MemberName.Basename, TypeParameters, Location);
135                                 current = current.ResolveAsTypeTerminal (this, false);
136                                 if (current == null)
137                                         return null;
138
139                                 CurrentType = current.Type;
140                         }
141 #endif
142
143                         return TypeBuilder;
144                 }
145
146                 public override bool Define ()
147                 {
148 #if GMCS_SOURCE
149                         if (IsGeneric) {
150                                 foreach (TypeParameter type_param in TypeParameters) {
151                                         if (!type_param.Resolve (this))
152                                                 return false;
153                                 }
154
155                                 foreach (TypeParameter type_param in TypeParameters) {
156                                         if (!type_param.DefineType (this))
157                                                 return false;
158                                 }
159
160                                 foreach (TypeParameter type_param in TypeParameters) {
161                                         if (!type_param.CheckDependencies ())
162                                                 return false;
163                                 }
164                         }
165 #endif
166                         member_cache = new MemberCache (TypeManager.multicast_delegate_type, this);
167
168                         // FIXME: POSSIBLY make this static, as it is always constant
169                         //
170                         Type [] const_arg_types = new Type [2];
171                         const_arg_types [0] = TypeManager.object_type;
172                         const_arg_types [1] = TypeManager.intptr_type;
173
174                         const MethodAttributes ctor_mattr = MethodAttributes.RTSpecialName | MethodAttributes.SpecialName |
175                                 MethodAttributes.HideBySig | MethodAttributes.Public;
176
177                         ConstructorBuilder = TypeBuilder.DefineConstructor (ctor_mattr,
178                                                                             CallingConventions.Standard,
179                                                                             const_arg_types);
180
181                         ConstructorBuilder.DefineParameter (1, ParameterAttributes.None, "object");
182                         ConstructorBuilder.DefineParameter (2, ParameterAttributes.None, "method");
183                         //
184                         // HACK because System.Reflection.Emit is lame
185                         //
186                         Parameter [] fixed_pars = new Parameter [2];
187                         fixed_pars [0] = new Parameter (TypeManager.object_type, "object",
188                                                         Parameter.Modifier.NONE, null, Location);
189                         fixed_pars [1] = new Parameter (TypeManager.intptr_type, "method", 
190                                                         Parameter.Modifier.NONE, null, Location);
191                         Parameters const_parameters = new Parameters (fixed_pars);
192                         const_parameters.Resolve (null);
193                         
194                         TypeManager.RegisterMethod (ConstructorBuilder, const_parameters);
195                         member_cache.AddMember (ConstructorBuilder, this);
196                         
197                         ConstructorBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);
198
199                         //
200                         // Here the various methods like Invoke, BeginInvoke etc are defined
201                         //
202                         // First, call the `out of band' special method for
203                         // defining recursively any types we need:
204                         
205                         if (!Parameters.Resolve (this))
206                                 return false;
207
208                         //
209                         // Invoke method
210                         //
211
212                         // Check accessibility
213                         foreach (Type partype in Parameters.Types){
214                                 if (!IsAccessibleAs (partype)) {
215                                         Report.SymbolRelatedToPreviousError (partype);
216                                         Report.Error (59, Location,
217                                                       "Inconsistent accessibility: parameter type `" +
218                                                       TypeManager.CSharpName (partype) + "' is less " +
219                                                           "accessible than delegate `" + GetSignatureForError () + "'");
220                                         return false;
221                                 }
222                         }
223                         
224                         ReturnType = ReturnType.ResolveAsTypeTerminal (this, false);
225                         if (ReturnType == null)
226                                 return false;
227
228                         ret_type = ReturnType.Type;
229             
230                         if (!IsAccessibleAs (ret_type)) {
231                                 Report.SymbolRelatedToPreviousError (ret_type);
232                                 Report.Error (58, Location,
233                                               "Inconsistent accessibility: return type `" +
234                                               TypeManager.CSharpName (ret_type) + "' is less " +
235                                               "accessible than delegate `" + GetSignatureForError () + "'");
236                                 return false;
237                         }
238
239                         if (RootContext.StdLib && (ret_type == TypeManager.arg_iterator_type || ret_type == TypeManager.typed_reference_type)) {
240                                 Method.Error1599 (Location, ret_type);
241                                 return false;
242                         }
243
244                         //
245                         // We don't have to check any others because they are all
246                         // guaranteed to be accessible - they are standard types.
247                         //
248                         
249                         CallingConventions cc = Parameters.CallingConvention;
250
251                         const MethodAttributes mattr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot;
252
253                         InvokeBuilder = TypeBuilder.DefineMethod ("Invoke", 
254                                                                   mattr,                     
255                                                                   cc,
256                                                                   ret_type,                  
257                                                                   Parameters.Types);
258                         
259                         InvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);
260
261                         TypeManager.RegisterMethod (InvokeBuilder, Parameters);
262                         member_cache.AddMember (InvokeBuilder, this);
263
264                         //
265                         // BeginInvoke
266                         //
267                         
268                         Parameters async_parameters = Parameters.MergeGenerated (Parameters, 
269                                 new Parameter (TypeManager.asynccallback_type, "callback", Parameter.Modifier.NONE, null, Location),
270                                 new Parameter (TypeManager.object_type, "object", Parameter.Modifier.NONE, null, Location));
271                         
272                         BeginInvokeBuilder = TypeBuilder.DefineMethod ("BeginInvoke",
273                                 mattr, cc, TypeManager.iasyncresult_type, async_parameters.Types);
274
275                         BeginInvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);
276                         TypeManager.RegisterMethod (BeginInvokeBuilder, async_parameters);
277                         member_cache.AddMember (BeginInvokeBuilder, this);
278
279                         //
280                         // EndInvoke is a bit more interesting, all the parameters labeled as
281                         // out or ref have to be duplicated here.
282                         //
283
284                         //
285                         // Define parameters, and count out/ref parameters
286                         //
287                         Parameters end_parameters;
288                         int out_params = 0;
289
290                         foreach (Parameter p in Parameters.FixedParameters) {
291                                 if ((p.ModFlags & Parameter.Modifier.ISBYREF) != 0)
292                                         ++out_params;
293                         }
294
295                         if (out_params > 0) {
296                                 Type [] end_param_types = new Type [out_params];
297                                 Parameter [] end_params = new Parameter [out_params ];
298
299                                 int param = 0; 
300                                 for (int i = 0; i < Parameters.FixedParameters.Length; ++i) {
301                                         Parameter p = Parameters.FixedParameters [i];
302                                         if ((p.ModFlags & Parameter.Modifier.ISBYREF) == 0)
303                                                 continue;
304
305                                         end_param_types [param] = p.ExternalType();
306                                         end_params [param] = p;
307                                         ++param;
308                                 }
309                                 end_parameters = Parameters.CreateFullyResolved (end_params, end_param_types);
310                         }
311                         else {
312                                 end_parameters = Parameters.EmptyReadOnlyParameters;
313                         }
314
315                         end_parameters = Parameters.MergeGenerated (end_parameters,
316                                 new Parameter (TypeManager.iasyncresult_type, "result", Parameter.Modifier.NONE, null, Location));
317                         
318                         //
319                         // Create method, define parameters, register parameters with type system
320                         //
321                         EndInvokeBuilder = TypeBuilder.DefineMethod ("EndInvoke", mattr, cc, ret_type, end_parameters.Types);
322                         EndInvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);
323
324                         end_parameters.ApplyAttributes (EndInvokeBuilder);
325                         TypeManager.RegisterMethod (EndInvokeBuilder, end_parameters);
326                         member_cache.AddMember (EndInvokeBuilder, this);
327
328                         return true;
329                 }
330
331                 public override void Emit ()
332                 {
333                         Parameters.ApplyAttributes (InvokeBuilder);
334
335                         Parameters p = (Parameters)TypeManager.GetParameterData (BeginInvokeBuilder);
336                         p.ApplyAttributes (BeginInvokeBuilder);
337
338                         if (OptAttributes != null) {
339                                 OptAttributes.Emit ();
340                         }
341
342                         base.Emit ();
343                 }
344
345                 protected override TypeAttributes TypeAttr {
346                         get {
347                                 return Modifiers.TypeAttr (ModFlags, IsTopLevel) |
348                                         TypeAttributes.Class | TypeAttributes.Sealed |
349                                         base.TypeAttr;
350                         }
351                 }
352
353                 public override string[] ValidAttributeTargets {
354                         get {
355                                 return attribute_targets;
356                         }
357                 }
358
359                 //TODO: duplicate
360                 protected override bool VerifyClsCompliance ()
361                 {
362                         if (!base.VerifyClsCompliance ()) {
363                                 return false;
364                         }
365
366                         Parameters.VerifyClsCompliance ();
367
368                         if (!AttributeTester.IsClsCompliant (ReturnType.Type)) {
369                                 Report.Error (3002, Location, "Return type of `{0}' is not CLS-compliant", GetSignatureForError ());
370                         }
371                         return true;
372                 }
373
374
375                 public static ConstructorInfo GetConstructor (Type container_type, Type delegate_type)
376                 {
377                         Type dt = delegate_type;
378 #if GMCS_SOURCE
379                         Type[] g_args = null;
380                         if (delegate_type.IsGenericType) {
381                                 g_args = delegate_type.GetGenericArguments ();
382                                 delegate_type = delegate_type.GetGenericTypeDefinition ();
383                         }
384 #endif
385
386                         Delegate d = TypeManager.LookupDelegate (delegate_type);
387                         if (d != null) {
388 #if GMCS_SOURCE
389                                 if (g_args != null)
390                                         return TypeBuilder.GetConstructor (dt, d.ConstructorBuilder);
391 #endif
392                                 return d.ConstructorBuilder;
393                         }
394
395                         Expression ml = Expression.MemberLookup (container_type,
396                                 null, dt, ConstructorInfo.ConstructorName, MemberTypes.Constructor,
397                                 BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, Location.Null);
398
399                         MethodGroupExpr mg = ml as MethodGroupExpr;
400                         if (mg == null) {
401                                 Report.Error (-100, Location.Null, "Internal error: could not find delegate constructor!");
402                                 // FIXME: null will cause a crash later
403                                 return null;
404                         }
405
406                         return (ConstructorInfo) mg.Methods[0];
407                 }
408
409                 //
410                 // Returns the MethodBase for "Invoke" from a delegate type, this is used
411                 // to extract the signature of a delegate.
412                 //
413                 public static MethodInfo GetInvokeMethod (Type container_type, Type delegate_type)
414                 {
415                         Type dt = delegate_type;
416 #if GMCS_SOURCE
417                         Type[] g_args = null;
418                         if (delegate_type.IsGenericType) {
419                                 g_args = delegate_type.GetGenericArguments ();
420                                 delegate_type = delegate_type.GetGenericTypeDefinition ();
421                         }
422 #endif
423                         Delegate d = TypeManager.LookupDelegate (delegate_type);
424                         if (d != null) {
425 #if GMCS_SOURCE
426                                 if (g_args != null) {
427                                         MethodInfo invoke = TypeBuilder.GetMethod (dt, d.InvokeBuilder);
428 #if MS_COMPATIBLE
429                                         Parameters p = (Parameters) d.Parameters.InflateTypes (g_args, g_args);
430                                         TypeManager.RegisterMethod (invoke, p);
431 #endif
432                                         return invoke;
433                                 }
434 #endif
435                                 return d.InvokeBuilder;
436                         }
437
438                         Expression ml = Expression.MemberLookup (container_type, null, dt,
439                                 "Invoke", Location.Null);
440
441                         MethodGroupExpr mg = ml as MethodGroupExpr;
442                         if (mg == null) {
443                                 Report.Error (-100, Location.Null, "Internal error: could not find Invoke method!");
444                                 // FIXME: null will cause a crash later
445                                 return null;
446                         }
447
448                         return (MethodInfo) mg.Methods[0];
449                 }
450
451                 public static bool IsTypeCovariant (Expression a, Type b)
452                 {
453                         Type a_type = a.Type;
454                         if (a_type == b)
455                                 return true;
456
457                         if (RootContext.Version == LanguageVersion.ISO_1)
458                                 return false;
459
460                         if (a.Type.IsValueType)
461                                 return false;
462
463                         return Convert.ImplicitReferenceConversionCore (
464                                 a, b);
465                 }
466                 
467                 /// <summary>
468                 ///  Verifies whether the method in question is compatible with the delegate
469                 ///  Returns the method itself if okay and null if not.
470                 /// </summary>
471                 public static MethodBase VerifyMethod (Type container_type, Type delegate_type,
472                                                        MethodGroupExpr old_mg, MethodBase mb,
473                                                        Location loc)
474                 {
475                         MethodInfo invoke_mb = GetInvokeMethod (container_type, delegate_type);
476                         ParameterData invoke_pd = TypeManager.GetParameterData (invoke_mb);
477
478 #if GMCS_SOURCE
479                         if (old_mg.type_arguments == null &&
480                             !TypeManager.InferTypeArguments (invoke_pd, ref mb))
481                                 return null;
482 #endif
483
484                         ParameterData pd = TypeManager.GetParameterData (mb);
485
486                         if (invoke_pd.Count != pd.Count)
487                                 return null;
488
489                         for (int i = pd.Count; i > 0; ) {
490                                 i--;
491
492                                 Type invoke_pd_type = invoke_pd.ParameterType (i);
493                                 Type pd_type = pd.ParameterType (i);
494                                 Parameter.Modifier invoke_pd_type_mod = invoke_pd.ParameterModifier (i);
495                                 Parameter.Modifier pd_type_mod = pd.ParameterModifier (i);
496
497                                 invoke_pd_type_mod &= ~Parameter.Modifier.PARAMS;
498                                 pd_type_mod &= ~Parameter.Modifier.PARAMS;
499
500                                 if (invoke_pd_type_mod != pd_type_mod)
501                                         return null;
502
503                                 if (invoke_pd_type == pd_type)
504                                         continue;
505
506                                 //if (!IsTypeCovariant (invoke_pd_type, pd_type))
507                                 //      return null;
508
509                                 if (RootContext.Version == LanguageVersion.ISO_1)
510                                         return null;
511                         }
512
513                         Type invoke_mb_retval = ((MethodInfo) invoke_mb).ReturnType;
514                         Type mb_retval = ((MethodInfo) mb).ReturnType;
515                         if (invoke_mb_retval == mb_retval)
516                                 return mb;
517
518                         //if (!IsTypeCovariant (mb_retval, invoke_mb_retval))
519                         //      return null;
520
521                         if (RootContext.Version == LanguageVersion.ISO_1) 
522                                 return null;
523
524                         return mb;
525                 }
526
527                 // <summary>
528                 //  Verifies whether the invocation arguments are compatible with the
529                 //  delegate's target method
530                 // </summary>
531                 public static bool VerifyApplicability (EmitContext ec, Type delegate_type,
532                                                         ArrayList args, Location loc)
533                 {
534                         int arg_count;
535
536                         if (args == null)
537                                 arg_count = 0;
538                         else
539                                 arg_count = args.Count;
540
541                         Expression ml = Expression.MemberLookup (
542                                 ec.ContainerType, delegate_type, "Invoke", loc);
543
544                         MethodGroupExpr me = ml as MethodGroupExpr;
545                         if (me == null) {
546                                 Report.Error (-100, loc, "Internal error: could not find Invoke method!" + delegate_type);
547                                 return false;
548                         }
549                         
550                         MethodBase mb = GetInvokeMethod (ec.ContainerType, delegate_type);
551                         ParameterData pd = TypeManager.GetParameterData (mb);
552
553                         int pd_count = pd.Count;
554
555                         bool params_method = pd.HasParams;
556                         bool is_params_applicable = false;
557                         me.DelegateType = delegate_type;
558                         bool is_applicable = me.IsApplicable (ec, args, arg_count, ref mb, ref is_params_applicable) == 0;
559
560                         if (!is_applicable && !params_method && arg_count != pd_count) {
561                                 Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
562                                         TypeManager.CSharpName (delegate_type), arg_count.ToString ());
563                                 return false;
564                         }
565
566                         return me.VerifyArgumentsCompat (
567                                         ec, ref args, arg_count, mb, 
568                                         is_params_applicable || (!is_applicable && params_method),
569                                         false, loc);
570                 }
571                 
572                 public static string FullDelegateDesc (MethodBase invoke_method)
573                 {
574                         return TypeManager.GetFullNameSignature (invoke_method).Replace (".Invoke", "");
575                 }
576                 
577                 public override MemberCache MemberCache {
578                         get {
579                                 return member_cache;
580                         }
581                 }
582
583                 public Expression InstanceExpression {
584                         get {
585                                 return instance_expr;
586                         }
587                         set {
588                                 instance_expr = value;
589                         }
590                 }
591
592                 public MethodBase TargetMethod {
593                         get {
594                                 return delegate_method;
595                         }
596                         set {
597                                 delegate_method = value;
598                         }
599                 }
600
601                 public Type TargetReturnType {
602                         get {
603                                 return ret_type;
604                         }
605                 }
606
607                 public override AttributeTargets AttributeTargets {
608                         get {
609                                 return AttributeTargets.Delegate;
610                         }
611                 }
612
613                 //
614                 //   Represents header string for documentation comment.
615                 //
616                 public override string DocCommentHeader {
617                         get { return "T:"; }
618                 }
619
620                 #region IMemberContainer Members
621
622                 string IMemberContainer.Name
623                 {
624                         get { throw new NotImplementedException (); }
625                 }
626
627                 Type IMemberContainer.Type
628                 {
629                         get { throw new NotImplementedException (); }
630                 }
631
632                 MemberCache IMemberContainer.BaseCache
633                 {
634                         get { throw new NotImplementedException (); }
635                 }
636
637                 bool IMemberContainer.IsInterface {
638                         get {
639                                 return false;
640                         }
641                 }
642
643                 MemberList IMemberContainer.GetMembers (MemberTypes mt, BindingFlags bf)
644                 {
645                         throw new NotImplementedException ();
646                 }
647
648                 #endregion
649         }
650
651         //
652         // Base class for `NewDelegate' and `ImplicitDelegateCreation'
653         //
654         public abstract class DelegateCreation : Expression, MethodGroupExpr.IErrorHandler
655         {
656                 protected ConstructorInfo constructor_method;
657                 protected MethodBase delegate_method;
658                 // We keep this to handle IsBase only
659                 protected MethodGroupExpr method_group;
660                 protected Expression delegate_instance_expression;
661
662                 ArrayList CreateDelegateMethodArguments (MethodInfo invoke_method)
663                 {
664                         ParameterData pd = TypeManager.GetParameterData (invoke_method);
665                         ArrayList delegate_arguments = new ArrayList (pd.Count);
666                         for (int i = 0; i < pd.Count; ++i) {
667                                 Argument.AType atype_modifier;
668                                 Type atype = pd.Types [i];
669                                 switch (pd.ParameterModifier (i)) {
670                                         case Parameter.Modifier.REF:
671                                                 atype_modifier = Argument.AType.Ref;
672                                                 atype = atype.GetElementType ();
673                                                 break;
674                                         case Parameter.Modifier.OUT:
675                                                 atype_modifier = Argument.AType.Out;
676                                                 atype = atype.GetElementType ();
677                                                 break;
678                                         case Parameter.Modifier.ARGLIST:
679                                                 // __arglist is not valid
680                                                 throw new InternalErrorException ("__arglist modifier");
681                                         default:
682                                                 atype_modifier = Argument.AType.Expression;
683                                                 break;
684                                 }
685                                 delegate_arguments.Add (new Argument (new TypeExpression (atype, loc), atype_modifier));
686                         }
687                         return delegate_arguments;
688                 }
689
690                 public override Expression DoResolve (EmitContext ec)
691                 {
692                         constructor_method = Delegate.GetConstructor (ec.ContainerType, type);
693
694                         MethodInfo invoke_method = Delegate.GetInvokeMethod (ec.ContainerType, type);
695                         method_group.DelegateType = type;
696                         method_group.CustomErrorHandler = this;
697
698                         ArrayList arguments = CreateDelegateMethodArguments (invoke_method);
699                         method_group = method_group.OverloadResolve (ec, ref arguments, false, loc);
700                         if (method_group == null)
701                                 return null;
702
703                         delegate_method = (MethodInfo) method_group;
704                         if (method_group is ExtensionMethodGroupExpr) {
705                                 ParameterData p = TypeManager.GetParameterData (delegate_method);
706                                 if (p.ExtensionMethodType.IsValueType) {
707                                         Report.Error (1113, loc, "Extension method `{0}' of value type `{1}' cannot be used to create delegates",
708                                                 TypeManager.CSharpSignature (delegate_method), TypeManager.CSharpName (p.ExtensionMethodType));
709                                 }
710                         }
711
712                         Expression ret_expr = new TypeExpression (((MethodInfo) delegate_method).ReturnType, loc);
713                         if (!Delegate.IsTypeCovariant (ret_expr, (invoke_method.ReturnType))) {
714                                 Error_ConversionFailed (ec, delegate_method, ret_expr);
715                         }
716
717                         DoResolveInstanceExpression (ec);
718                         eclass = ExprClass.Value;
719                         return this;
720                 }
721
722                 void DoResolveInstanceExpression (EmitContext ec)
723                 {
724                         //
725                         // Argument is another delegate
726                         //
727                         if (delegate_instance_expression != null)
728                                 return;
729                         
730                         if (method_group.InstanceExpression != null)
731                                 delegate_instance_expression = method_group.InstanceExpression;
732                         else if (!ec.IsStatic)
733                                 delegate_instance_expression = ec.GetThis (loc);
734
735                         if (delegate_instance_expression != null && delegate_instance_expression.Type.IsValueType)
736                                 delegate_instance_expression = new BoxedCast (
737                                         delegate_instance_expression, TypeManager.object_type);
738                 }
739                 
740                 public override void Emit (EmitContext ec)
741                 {
742                         if (delegate_instance_expression == null || delegate_method.IsStatic)
743                                 ec.ig.Emit (OpCodes.Ldnull);
744                         else
745                                 delegate_instance_expression.Emit (ec);
746
747                         if (!delegate_method.DeclaringType.IsSealed && delegate_method.IsVirtual && !method_group.IsBase) {
748                                 ec.ig.Emit (OpCodes.Dup);
749                                 ec.ig.Emit (OpCodes.Ldvirtftn, (MethodInfo) delegate_method);
750                         } else
751                                 ec.ig.Emit (OpCodes.Ldftn, (MethodInfo) delegate_method);
752                         ec.ig.Emit (OpCodes.Newobj, constructor_method);
753                 }
754
755                 void Error_ConversionFailed (EmitContext ec, MethodBase method, Expression return_type)
756                 {
757                         MethodInfo invoke_method = Delegate.GetInvokeMethod (ec.ContainerType, type);
758                         string member_name = delegate_instance_expression != null ?
759                                 Delegate.FullDelegateDesc (method) :
760                                 TypeManager.GetFullNameSignature (method);
761
762                         Report.SymbolRelatedToPreviousError (type);
763                         Report.SymbolRelatedToPreviousError (method);
764                         if (RootContext.Version == LanguageVersion.ISO_1) {
765                                 Report.Error (410, loc, "A method or delegate `{0} {1}' parameters and return type must be same as delegate `{2} {3}' parameters and return type",
766                                         TypeManager.CSharpName (((MethodInfo) method).ReturnType), member_name,
767                                         TypeManager.CSharpName (invoke_method.ReturnType), Delegate.FullDelegateDesc (invoke_method));
768                                 return;
769                         }
770                         if (return_type == null) {
771                                 Report.Error (123, loc, "A method or delegate `{0}' parameters do not match delegate `{1}' parameters",
772                                         member_name, Delegate.FullDelegateDesc (invoke_method));
773                                 return;
774                         }
775
776                         Report.Error (407, loc, "A method or delegate `{0} {1}' return type does not match delegate `{2} {3}' return type",
777                                 return_type.GetSignatureForError (), member_name,
778                                 TypeManager.CSharpName (invoke_method.ReturnType), Delegate.FullDelegateDesc (invoke_method));
779                 }
780
781                 public static MethodBase ImplicitStandardConversionExists (MethodGroupExpr mg, Type target_type)
782                 {
783                         foreach (MethodInfo mi in mg.Methods){
784                                 MethodBase mb = Delegate.VerifyMethod (mg.DeclaringType, target_type, mg, mi, Location.Null);
785                                 if (mb != null)
786                                         return mb;
787                         }
788                         return null;
789                 }
790
791                 #region IErrorHandler Members
792
793                 public bool NoExactMatch (EmitContext ec, MethodBase method)
794                 {
795                         if (TypeManager.IsGenericMethod (method))
796                                 return false;
797
798                         Error_ConversionFailed (ec, method, null);
799                         return true;
800                 }
801
802                 #endregion
803         }
804
805         //
806         // Created from the conversion code
807         //
808         public class ImplicitDelegateCreation : DelegateCreation
809         {
810                 ImplicitDelegateCreation (Type t, MethodGroupExpr mg, Location l)
811                 {
812                         type = t;
813                         this.method_group = mg;
814                         loc = l;
815                 }
816
817                 static public Expression Create (EmitContext ec, MethodGroupExpr mge,
818                                                  Type target_type, Location loc)
819                 {
820                         ImplicitDelegateCreation d = new ImplicitDelegateCreation (target_type, mge, loc);
821                         return d.DoResolve (ec);
822                 }
823         }
824         
825         //
826         // A delegate-creation-expression, invoked from the `New' class 
827         //
828         public class NewDelegate : DelegateCreation
829         {
830                 public ArrayList Arguments;
831
832                 //
833                 // This constructor is invoked from the `New' expression
834                 //
835                 public NewDelegate (Type type, ArrayList Arguments, Location loc)
836                 {
837                         this.type = type;
838                         this.Arguments = Arguments;
839                         this.loc  = loc; 
840                 }
841
842                 public override Expression DoResolve (EmitContext ec)
843                 {
844                         if (Arguments == null) {
845                                 Error_InvalidDelegateArgument ();
846                                 return null;
847                         }
848
849                         Argument a = (Argument) Arguments [0];
850                         if (!a.ResolveMethodGroup (ec))
851                                 return null;
852                         
853                         Expression e = a.Expr;
854                         if (e is AnonymousMethodExpression && RootContext.Version != LanguageVersion.ISO_1) {
855                                 e = ((AnonymousMethodExpression) e).Compatible (ec, type);
856                                 if (e == null)
857                                         return null;
858                                 return e.Resolve (ec);
859                         }
860
861                         method_group = e as MethodGroupExpr;
862                         if (method_group == null) {
863                                 if (!TypeManager.IsDelegateType (e.Type)) {
864                                         Report.Error (149, loc, "Method name expected");
865                                         return null;
866                                 }
867
868                                 //
869                                 // An argument is not a method but another delegate
870                                 //
871                                 delegate_instance_expression = e;
872                                 method_group = new MethodGroupExpr (new MemberInfo [] { 
873                                         Delegate.GetInvokeMethod (ec.ContainerType, e.Type) }, e.Type, loc);
874                         }
875
876                         if (base.DoResolve (ec) == null)
877                                 return null;
878
879                         if (TypeManager.IsNullableType (method_group.DeclaringType)) {
880                                 Report.Error (1728, loc, "Cannot use method `{0}' as delegate creation expression because it is member of Nullable type",
881                                         TypeManager.GetFullNameSignature (delegate_method));
882                         }
883
884                         if (Invocation.IsMethodExcluded (delegate_method)) {
885                                 Report.SymbolRelatedToPreviousError (delegate_method);
886                                 Report.Error (1618, loc, "Cannot create delegate with `{0}' because it has a Conditional attribute",
887                                         TypeManager.CSharpSignature (delegate_method));
888                         }
889
890                         return this;
891                 }
892
893                 void Error_InvalidDelegateArgument ()
894                 {
895                         Report.Error (149, loc, "Method name expected");
896                 }
897         }
898
899         public class DelegateInvocation : ExpressionStatement {
900
901                 readonly Expression InstanceExpr;
902                 readonly ArrayList  Arguments;
903
904                 MethodBase method;
905                 
906                 public DelegateInvocation (Expression instance_expr, ArrayList args, Location loc)
907                 {
908                         this.InstanceExpr = instance_expr;
909                         this.Arguments = args;
910                         this.loc = loc;
911                 }
912
913                 public override Expression DoResolve (EmitContext ec)
914                 {
915                         if (InstanceExpr is EventExpr) {
916                                 
917                                 EventInfo ei = ((EventExpr) InstanceExpr).EventInfo;
918                                 
919                                 Expression ml = MemberLookup (
920                                         ec.ContainerType, ec.ContainerType, ei.Name,
921                                         MemberTypes.Event, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
922
923                                 if (ml == null) {
924                                         //
925                                         // If this is the case, then the Event does not belong 
926                                         // to this Type and so, according to the spec
927                                         // cannot be accessed directly
928                                         //
929                                         // Note that target will not appear as an EventExpr
930                                         // in the case it is being referenced within the same type container;
931                                         // it will appear as a FieldExpr in that case.
932                                         //
933                                         
934                                         Assign.error70 (ei, loc);
935                                         return null;
936                                 }
937                         }
938                         
939                         
940                         Type del_type = InstanceExpr.Type;
941                         if (del_type == null)
942                                 return null;
943                         
944                         if (Arguments != null){
945                                 foreach (Argument a in Arguments){
946                                         if (!a.Resolve (ec, loc))
947                                                 return null;
948                                 }
949                         }
950                         
951                         if (!Delegate.VerifyApplicability (ec, del_type, Arguments, loc))
952                                 return null;
953
954                         method = Delegate.GetInvokeMethod (ec.ContainerType, del_type);
955                         type = ((MethodInfo) method).ReturnType;
956                         eclass = ExprClass.Value;
957                         
958                         return this;
959                 }
960
961                 public override void Emit (EmitContext ec)
962                 {
963                         //
964                         // Invocation on delegates call the virtual Invoke member
965                         // so we are always `instance' calls
966                         //
967                         Invocation.EmitCall (ec, false, InstanceExpr, method, Arguments, loc);
968                 }
969
970                 public override void EmitStatement (EmitContext ec)
971                 {
972                         Emit (ec);
973                         // 
974                         // Pop the return value if there is one
975                         //
976                         if (method is MethodInfo){
977                                 Type ret = ((MethodInfo)method).ReturnType;
978                                 if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
979                                         ec.ig.Emit (OpCodes.Pop);
980                         }
981                 }
982
983         }
984 }