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