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