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