2009-11-02 Jb Evain <jbevain@novell.com>
[mcs.git] / mcs / delegate.cs
blob6fde0de7754a0866a056dccf8b154ad60b5f7299
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
11 // Copyright 2001 Ximian, Inc (http://www.ximian.com)
12 // Copyright 2003-2009 Novell, Inc (http://www.novell.com)
15 using System;
16 using System.Collections;
17 using System.Reflection;
18 using System.Reflection.Emit;
19 using System.Text;
21 namespace Mono.CSharp {
24 // Delegate container implementation
26 public class Delegate : TypeContainer
28 FullNamedExpression ReturnType;
29 public ParametersCompiled Parameters;
31 public ConstructorBuilder ConstructorBuilder;
32 public MethodBuilder InvokeBuilder;
33 public MethodBuilder BeginInvokeBuilder;
34 public MethodBuilder EndInvokeBuilder;
36 Type ret_type;
38 static string[] attribute_targets = new string [] { "type", "return" };
40 Expression instance_expr;
41 MethodBase delegate_method;
42 ReturnParameter return_attributes;
44 const MethodAttributes mattr = MethodAttributes.Public | MethodAttributes.HideBySig |
45 MethodAttributes.Virtual | MethodAttributes.NewSlot;
47 const int AllowedModifiers =
48 Modifiers.NEW |
49 Modifiers.PUBLIC |
50 Modifiers.PROTECTED |
51 Modifiers.INTERNAL |
52 Modifiers.UNSAFE |
53 Modifiers.PRIVATE;
55 public Delegate (NamespaceEntry ns, DeclSpace parent, FullNamedExpression type,
56 int mod_flags, MemberName name, ParametersCompiled param_list,
57 Attributes attrs)
58 : base (ns, parent, name, attrs, Kind.Delegate)
61 this.ReturnType = type;
62 ModFlags = Modifiers.Check (AllowedModifiers, mod_flags,
63 IsTopLevel ? Modifiers.INTERNAL :
64 Modifiers.PRIVATE, name.Location, Report);
65 Parameters = param_list;
68 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa)
70 if (a.Target == AttributeTargets.ReturnValue) {
71 if (return_attributes == null)
72 return_attributes = new ReturnParameter (InvokeBuilder, Location);
74 return_attributes.ApplyAttributeBuilder (a, cb, pa);
75 return;
78 base.ApplyAttributeBuilder (a, cb, pa);
81 public override AttributeTargets AttributeTargets {
82 get {
83 return AttributeTargets.Delegate;
87 public override bool Define ()
89 if (IsGeneric) {
90 foreach (TypeParameter type_param in TypeParameters) {
91 if (!type_param.Resolve (this))
92 return false;
95 foreach (TypeParameter type_param in TypeParameters) {
96 if (!type_param.DefineType (this))
97 return false;
101 member_cache = new MemberCache (TypeManager.multicast_delegate_type, this);
103 // FIXME: POSSIBLY make this static, as it is always constant
105 Type [] const_arg_types = new Type [2];
106 const_arg_types [0] = TypeManager.object_type;
107 const_arg_types [1] = TypeManager.intptr_type;
109 const MethodAttributes ctor_mattr = MethodAttributes.RTSpecialName | MethodAttributes.SpecialName |
110 MethodAttributes.HideBySig | MethodAttributes.Public;
112 ConstructorBuilder = TypeBuilder.DefineConstructor (ctor_mattr,
113 CallingConventions.Standard,
114 const_arg_types);
116 ConstructorBuilder.DefineParameter (1, ParameterAttributes.None, "object");
117 ConstructorBuilder.DefineParameter (2, ParameterAttributes.None, "method");
119 // HACK because System.Reflection.Emit is lame
121 IParameterData [] fixed_pars = new IParameterData [] {
122 new ParameterData ("object", Parameter.Modifier.NONE),
123 new ParameterData ("method", Parameter.Modifier.NONE)
126 AParametersCollection const_parameters = new ParametersImported (
127 fixed_pars,
128 new Type[] { TypeManager.object_type, TypeManager.intptr_type });
130 TypeManager.RegisterMethod (ConstructorBuilder, const_parameters);
131 member_cache.AddMember (ConstructorBuilder, this);
133 ConstructorBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);
136 // Here the various methods like Invoke, BeginInvoke etc are defined
138 // First, call the `out of band' special method for
139 // defining recursively any types we need:
141 if (!Parameters.Resolve (this))
142 return false;
145 // Invoke method
148 // Check accessibility
149 foreach (Type partype in Parameters.Types){
150 if (!IsAccessibleAs (partype)) {
151 Report.SymbolRelatedToPreviousError (partype);
152 Report.Error (59, Location,
153 "Inconsistent accessibility: parameter type `{0}' is less accessible than delegate `{1}'",
154 TypeManager.CSharpName (partype),
155 GetSignatureForError ());
156 return false;
160 ReturnType = ReturnType.ResolveAsTypeTerminal (this, false);
161 if (ReturnType == null)
162 return false;
164 ret_type = ReturnType.Type;
166 if (!IsAccessibleAs (ret_type)) {
167 Report.SymbolRelatedToPreviousError (ret_type);
168 Report.Error (58, Location,
169 "Inconsistent accessibility: return type `" +
170 TypeManager.CSharpName (ret_type) + "' is less " +
171 "accessible than delegate `" + GetSignatureForError () + "'");
172 return false;
175 CheckProtectedModifier ();
177 if (RootContext.StdLib && TypeManager.IsSpecialType (ret_type)) {
178 Method.Error1599 (Location, ret_type, Report);
179 return false;
182 TypeManager.CheckTypeVariance (ret_type, Variance.Covariant, this);
185 // We don't have to check any others because they are all
186 // guaranteed to be accessible - they are standard types.
189 CallingConventions cc = Parameters.CallingConvention;
191 InvokeBuilder = TypeBuilder.DefineMethod ("Invoke",
192 mattr,
194 ret_type,
195 Parameters.GetEmitTypes ());
197 InvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);
199 TypeManager.RegisterMethod (InvokeBuilder, Parameters);
200 member_cache.AddMember (InvokeBuilder, this);
203 // Don't emit async method for compiler generated delegates (e.g. dynamic site containers)
205 if (TypeManager.iasyncresult_type != null && TypeManager.asynccallback_type != null && !IsCompilerGenerated) {
206 DefineAsyncMethods (cc);
209 return true;
212 void DefineAsyncMethods (CallingConventions cc)
215 // BeginInvoke
217 ParametersCompiled async_parameters = ParametersCompiled.MergeGenerated (Parameters, false,
218 new Parameter [] {
219 new Parameter (null, "callback", Parameter.Modifier.NONE, null, Location),
220 new Parameter (null, "object", Parameter.Modifier.NONE, null, Location)
222 new Type [] {
223 TypeManager.asynccallback_type,
224 TypeManager.object_type
228 BeginInvokeBuilder = TypeBuilder.DefineMethod ("BeginInvoke",
229 mattr, cc, TypeManager.iasyncresult_type, async_parameters.GetEmitTypes ());
231 BeginInvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);
232 TypeManager.RegisterMethod (BeginInvokeBuilder, async_parameters);
233 member_cache.AddMember (BeginInvokeBuilder, this);
236 // EndInvoke is a bit more interesting, all the parameters labeled as
237 // out or ref have to be duplicated here.
241 // Define parameters, and count out/ref parameters
243 ParametersCompiled end_parameters;
244 int out_params = 0;
246 foreach (Parameter p in Parameters.FixedParameters) {
247 if ((p.ModFlags & Parameter.Modifier.ISBYREF) != 0)
248 ++out_params;
251 if (out_params > 0) {
252 Type [] end_param_types = new Type [out_params];
253 Parameter[] end_params = new Parameter [out_params];
255 int param = 0;
256 for (int i = 0; i < Parameters.FixedParameters.Length; ++i) {
257 Parameter p = Parameters [i];
258 if ((p.ModFlags & Parameter.Modifier.ISBYREF) == 0)
259 continue;
261 end_param_types [param] = Parameters.Types [i];
262 end_params [param] = p;
263 ++param;
265 end_parameters = ParametersCompiled.CreateFullyResolved (end_params, end_param_types);
266 } else {
267 end_parameters = ParametersCompiled.EmptyReadOnlyParameters;
270 end_parameters = ParametersCompiled.MergeGenerated (end_parameters, false,
271 new Parameter (null, "result", Parameter.Modifier.NONE, null, Location), TypeManager.iasyncresult_type);
274 // Create method, define parameters, register parameters with type system
276 EndInvokeBuilder = TypeBuilder.DefineMethod ("EndInvoke", mattr, cc, ret_type, end_parameters.GetEmitTypes ());
277 EndInvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);
279 end_parameters.ApplyAttributes (EndInvokeBuilder);
280 TypeManager.RegisterMethod (EndInvokeBuilder, end_parameters);
281 member_cache.AddMember (EndInvokeBuilder, this);
284 public override void Emit ()
286 if (TypeManager.IsDynamicType (ret_type)) {
287 return_attributes = new ReturnParameter (InvokeBuilder, Location);
288 return_attributes.EmitPredefined (PredefinedAttributes.Get.Dynamic, Location);
291 Parameters.ApplyAttributes (InvokeBuilder);
293 if (BeginInvokeBuilder != null) {
294 ParametersCompiled p = (ParametersCompiled) TypeManager.GetParameterData (BeginInvokeBuilder);
295 p.ApplyAttributes (BeginInvokeBuilder);
298 if (OptAttributes != null) {
299 OptAttributes.Emit ();
302 base.Emit ();
305 protected override TypeAttributes TypeAttr {
306 get {
307 return Modifiers.TypeAttr (ModFlags, IsTopLevel) |
308 TypeAttributes.Class | TypeAttributes.Sealed |
309 base.TypeAttr;
313 public override string[] ValidAttributeTargets {
314 get {
315 return attribute_targets;
319 //TODO: duplicate
320 protected override bool VerifyClsCompliance ()
322 if (!base.VerifyClsCompliance ()) {
323 return false;
326 Parameters.VerifyClsCompliance ();
328 if (!AttributeTester.IsClsCompliant (ReturnType.Type)) {
329 Report.Warning (3002, 1, Location, "Return type of `{0}' is not CLS-compliant",
330 GetSignatureForError ());
332 return true;
336 public static ConstructorInfo GetConstructor (CompilerContext ctx, Type container_type, Type delegate_type)
338 Type dt = delegate_type;
339 Type[] g_args = null;
340 if (TypeManager.IsGenericType (delegate_type)) {
341 g_args = TypeManager.GetTypeArguments (delegate_type);
342 delegate_type = TypeManager.DropGenericTypeArguments (delegate_type);
345 Delegate d = TypeManager.LookupDelegate (delegate_type);
346 if (d != null) {
347 if (g_args != null)
348 return TypeBuilder.GetConstructor (dt, d.ConstructorBuilder);
350 return d.ConstructorBuilder;
353 Expression ml = Expression.MemberLookup (ctx, container_type,
354 null, dt, ConstructorInfo.ConstructorName, MemberTypes.Constructor,
355 BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, Location.Null);
357 MethodGroupExpr mg = ml as MethodGroupExpr;
358 if (mg == null) {
359 ctx.Report.Error (-100, Location.Null, "Internal error: could not find delegate constructor!");
360 // FIXME: null will cause a crash later
361 return null;
364 return (ConstructorInfo) mg.Methods[0];
368 // Returns the MethodBase for "Invoke" from a delegate type, this is used
369 // to extract the signature of a delegate.
371 public static MethodInfo GetInvokeMethod (CompilerContext ctx, Type container_type, Type delegate_type)
373 Type dt = delegate_type;
375 Type[] g_args = null;
376 if (TypeManager.IsGenericType (delegate_type)) {
377 g_args = TypeManager.GetTypeArguments (delegate_type);
378 delegate_type = TypeManager.DropGenericTypeArguments (delegate_type);
381 Delegate d = TypeManager.LookupDelegate (delegate_type);
382 MethodInfo invoke;
383 if (d != null) {
384 if (g_args != null) {
385 invoke = TypeBuilder.GetMethod (dt, d.InvokeBuilder);
386 #if MS_COMPATIBLE
387 ParametersCompiled p = (ParametersCompiled) d.Parameters.InflateTypes (g_args, g_args);
388 TypeManager.RegisterMethod (invoke, p);
389 #endif
390 return invoke;
392 return d.InvokeBuilder;
395 Expression ml = Expression.MemberLookup (ctx, container_type, null, dt,
396 "Invoke", Location.Null);
398 MethodGroupExpr mg = ml as MethodGroupExpr;
399 if (mg == null) {
400 ctx.Report.Error (-100, Location.Null, "Internal error: could not find Invoke method!");
401 // FIXME: null will cause a crash later
402 return null;
405 invoke = (MethodInfo) mg.Methods[0];
406 #if MS_COMPATIBLE
407 if (g_args != null) {
408 AParametersCollection p = TypeManager.GetParameterData (invoke);
409 p = p.InflateTypes (g_args, g_args);
410 TypeManager.RegisterMethod (invoke, p);
411 return invoke;
413 #endif
415 return invoke;
419 // 15.2 Delegate compatibility
421 public static bool IsTypeCovariant (Expression a, Type b)
424 // For each value parameter (a parameter with no ref or out modifier), an
425 // identity conversion or implicit reference conversion exists from the
426 // parameter type in D to the corresponding parameter type in M
428 if (a.Type == b)
429 return true;
431 if (RootContext.Version == LanguageVersion.ISO_1)
432 return false;
434 return Convert.ImplicitReferenceConversionExists (a, b);
437 public static string FullDelegateDesc (MethodBase invoke_method)
439 return TypeManager.GetFullNameSignature (invoke_method).Replace (".Invoke", "");
442 public Expression InstanceExpression {
443 get {
444 return instance_expr;
446 set {
447 instance_expr = value;
451 public MethodBase TargetMethod {
452 get {
453 return delegate_method;
455 set {
456 delegate_method = value;
460 public Type TargetReturnType {
461 get {
462 return ret_type;
468 // Base class for `NewDelegate' and `ImplicitDelegateCreation'
470 public abstract class DelegateCreation : Expression, MethodGroupExpr.IErrorHandler
472 protected ConstructorInfo constructor_method;
473 protected MethodInfo delegate_method;
474 // We keep this to handle IsBase only
475 protected MethodGroupExpr method_group;
476 protected Expression delegate_instance_expression;
478 // TODO: Should either cache it or use interface to abstract it
479 public static Arguments CreateDelegateMethodArguments (AParametersCollection pd, Location loc)
481 Arguments delegate_arguments = new Arguments (pd.Count);
482 for (int i = 0; i < pd.Count; ++i) {
483 Argument.AType atype_modifier;
484 Type atype = pd.Types [i];
485 switch (pd.FixedParameters [i].ModFlags) {
486 case Parameter.Modifier.REF:
487 atype_modifier = Argument.AType.Ref;
488 //atype = atype.GetElementType ();
489 break;
490 case Parameter.Modifier.OUT:
491 atype_modifier = Argument.AType.Out;
492 //atype = atype.GetElementType ();
493 break;
494 default:
495 atype_modifier = 0;
496 break;
498 delegate_arguments.Add (new Argument (new TypeExpression (atype, loc), atype_modifier));
500 return delegate_arguments;
503 public override Expression CreateExpressionTree (ResolveContext ec)
505 MemberAccess ma = new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "Delegate", loc), "CreateDelegate", loc);
507 Arguments args = new Arguments (3);
508 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
509 args.Add (new Argument (new NullLiteral (loc)));
510 args.Add (new Argument (new TypeOfMethod (delegate_method, loc)));
511 Expression e = new Invocation (ma, args).Resolve (ec);
512 if (e == null)
513 return null;
515 e = Convert.ExplicitConversion (ec, e, type, loc);
516 if (e == null)
517 return null;
519 return e.CreateExpressionTree (ec);
522 public override Expression DoResolve (ResolveContext ec)
524 constructor_method = Delegate.GetConstructor (ec.Compiler, ec.CurrentType, type);
526 MethodInfo invoke_method = Delegate.GetInvokeMethod (ec.Compiler, ec.CurrentType, type);
527 method_group.DelegateType = type;
528 method_group.CustomErrorHandler = this;
530 Arguments arguments = CreateDelegateMethodArguments (TypeManager.GetParameterData (invoke_method), loc);
531 method_group = method_group.OverloadResolve (ec, ref arguments, false, loc);
532 if (method_group == null)
533 return null;
535 delegate_method = (MethodInfo) method_group;
537 if (TypeManager.IsNullableType (delegate_method.DeclaringType)) {
538 ec.Report.Error (1728, loc, "Cannot create delegate from method `{0}' because it is a member of System.Nullable<T> type",
539 TypeManager.GetFullNameSignature (delegate_method));
540 return null;
543 Invocation.IsSpecialMethodInvocation (ec, delegate_method, loc);
545 ExtensionMethodGroupExpr emg = method_group as ExtensionMethodGroupExpr;
546 if (emg != null) {
547 delegate_instance_expression = emg.ExtensionExpression;
548 Type e_type = delegate_instance_expression.Type;
549 if (TypeManager.IsValueType (e_type)) {
550 ec.Report.Error (1113, loc, "Extension method `{0}' of value type `{1}' cannot be used to create delegates",
551 TypeManager.CSharpSignature (delegate_method), TypeManager.CSharpName (e_type));
555 Type rt = TypeManager.TypeToCoreType (delegate_method.ReturnType);
556 Expression ret_expr = new TypeExpression (rt, loc);
557 if (!Delegate.IsTypeCovariant (ret_expr, (TypeManager.TypeToCoreType (invoke_method.ReturnType)))) {
558 Error_ConversionFailed (ec, delegate_method, ret_expr);
561 if (Invocation.IsMethodExcluded (delegate_method, loc)) {
562 ec.Report.SymbolRelatedToPreviousError (delegate_method);
563 MethodOrOperator m = TypeManager.GetMethod (delegate_method) as MethodOrOperator;
564 if (m != null && m.IsPartialDefinition) {
565 ec.Report.Error (762, loc, "Cannot create delegate from partial method declaration `{0}'",
566 TypeManager.CSharpSignature (delegate_method));
567 } else {
568 ec.Report.Error (1618, loc, "Cannot create delegate with `{0}' because it has a Conditional attribute",
569 TypeManager.CSharpSignature (delegate_method));
573 DoResolveInstanceExpression (ec);
574 eclass = ExprClass.Value;
575 return this;
578 void DoResolveInstanceExpression (ResolveContext ec)
581 // Argument is another delegate
583 if (delegate_instance_expression != null)
584 return;
586 if (method_group.IsStatic) {
587 delegate_instance_expression = null;
588 return;
591 Expression instance = method_group.InstanceExpression;
592 if (instance != null && instance != EmptyExpression.Null) {
593 delegate_instance_expression = instance;
594 Type instance_type = delegate_instance_expression.Type;
595 if (TypeManager.IsValueType (instance_type) || TypeManager.IsGenericParameter (instance_type)) {
596 delegate_instance_expression = new BoxedCast (
597 delegate_instance_expression, TypeManager.object_type);
599 } else {
600 delegate_instance_expression = ec.GetThis (loc);
604 public override void Emit (EmitContext ec)
606 if (delegate_instance_expression == null)
607 ec.ig.Emit (OpCodes.Ldnull);
608 else
609 delegate_instance_expression.Emit (ec);
611 if (!delegate_method.DeclaringType.IsSealed && delegate_method.IsVirtual && !method_group.IsBase) {
612 ec.ig.Emit (OpCodes.Dup);
613 ec.ig.Emit (OpCodes.Ldvirtftn, delegate_method);
614 } else {
615 ec.ig.Emit (OpCodes.Ldftn, delegate_method);
618 ec.ig.Emit (OpCodes.Newobj, constructor_method);
621 void Error_ConversionFailed (ResolveContext ec, MethodBase method, Expression return_type)
623 MethodInfo invoke_method = Delegate.GetInvokeMethod (ec.Compiler, ec.CurrentType, type);
624 string member_name = delegate_instance_expression != null ?
625 Delegate.FullDelegateDesc (method) :
626 TypeManager.GetFullNameSignature (method);
628 ec.Report.SymbolRelatedToPreviousError (type);
629 ec.Report.SymbolRelatedToPreviousError (method);
630 if (RootContext.Version == LanguageVersion.ISO_1) {
631 ec.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",
632 TypeManager.CSharpName (((MethodInfo) method).ReturnType), member_name,
633 TypeManager.CSharpName (invoke_method.ReturnType), Delegate.FullDelegateDesc (invoke_method));
634 return;
636 if (return_type == null) {
637 ec.Report.Error (123, loc, "A method or delegate `{0}' parameters do not match delegate `{1}' parameters",
638 member_name, Delegate.FullDelegateDesc (invoke_method));
639 return;
642 ec.Report.Error (407, loc, "A method or delegate `{0} {1}' return type does not match delegate `{2} {3}' return type",
643 return_type.GetSignatureForError (), member_name,
644 TypeManager.CSharpName (invoke_method.ReturnType), Delegate.FullDelegateDesc (invoke_method));
647 public static bool ImplicitStandardConversionExists (ResolveContext ec, MethodGroupExpr mg, Type target_type)
649 if (target_type == TypeManager.delegate_type || target_type == TypeManager.multicast_delegate_type)
650 return false;
652 mg.DelegateType = target_type;
653 MethodInfo invoke = Delegate.GetInvokeMethod (ec.Compiler, null, target_type);
655 Arguments arguments = CreateDelegateMethodArguments (TypeManager.GetParameterData (invoke), mg.Location);
656 return mg.OverloadResolve (ec, ref arguments, true, mg.Location) != null;
659 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
661 if (delegate_instance_expression != null)
662 delegate_instance_expression.MutateHoistedGenericType (storey);
664 delegate_method = storey.MutateGenericMethod (delegate_method);
665 constructor_method = storey.MutateConstructor (constructor_method);
668 #region IErrorHandler Members
670 public bool NoExactMatch (ResolveContext ec, MethodBase method)
672 if (TypeManager.IsGenericMethod (method))
673 return false;
675 Error_ConversionFailed (ec, method, null);
676 return true;
679 public bool AmbiguousCall (ResolveContext ec, MethodBase ambiguous)
681 return false;
684 #endregion
688 // Created from the conversion code
690 public class ImplicitDelegateCreation : DelegateCreation
692 ImplicitDelegateCreation (Type t, MethodGroupExpr mg, Location l)
694 type = t;
695 this.method_group = mg;
696 loc = l;
699 static public Expression Create (ResolveContext ec, MethodGroupExpr mge,
700 Type target_type, Location loc)
702 ImplicitDelegateCreation d = new ImplicitDelegateCreation (target_type, mge, loc);
703 return d.DoResolve (ec);
708 // A delegate-creation-expression, invoked from the `New' class
710 public class NewDelegate : DelegateCreation
712 public Arguments Arguments;
715 // This constructor is invoked from the `New' expression
717 public NewDelegate (Type type, Arguments Arguments, Location loc)
719 this.type = type;
720 this.Arguments = Arguments;
721 this.loc = loc;
724 public override Expression DoResolve (ResolveContext ec)
726 if (Arguments == null || Arguments.Count != 1) {
727 ec.Report.Error (149, loc, "Method name expected");
728 return null;
731 Argument a = Arguments [0];
732 if (!a.ResolveMethodGroup (ec))
733 return null;
735 Expression e = a.Expr;
737 AnonymousMethodExpression ame = e as AnonymousMethodExpression;
738 if (ame != null && RootContext.Version != LanguageVersion.ISO_1) {
739 e = ame.Compatible (ec, type);
740 if (e == null)
741 return null;
743 return e.Resolve (ec);
746 method_group = e as MethodGroupExpr;
747 if (method_group == null) {
748 if (!TypeManager.IsDelegateType (e.Type)) {
749 e.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup | ResolveFlags.Type, loc);
750 return null;
754 // An argument is not a method but another delegate
756 delegate_instance_expression = e;
757 method_group = new MethodGroupExpr (new MemberInfo [] {
758 Delegate.GetInvokeMethod (ec.Compiler, ec.CurrentType, e.Type) }, e.Type, loc);
761 return base.DoResolve (ec);
766 // Invocation converted to delegate Invoke call
768 class DelegateInvocation : ExpressionStatement
770 readonly Expression InstanceExpr;
771 Arguments arguments;
772 MethodInfo method;
774 public DelegateInvocation (Expression instance_expr, Arguments args, Location loc)
776 this.InstanceExpr = instance_expr;
777 this.arguments = args;
778 this.loc = loc;
781 public override Expression CreateExpressionTree (ResolveContext ec)
783 Arguments args = Arguments.CreateForExpressionTree (ec, this.arguments,
784 InstanceExpr.CreateExpressionTree (ec));
786 return CreateExpressionFactoryCall (ec, "Invoke", args);
789 public override Expression DoResolve (ResolveContext ec)
791 if (InstanceExpr is EventExpr) {
792 ((EventExpr) InstanceExpr).Error_CannotAssign (ec);
793 return null;
796 Type del_type = InstanceExpr.Type;
797 if (del_type == null)
798 return null;
800 method = Delegate.GetInvokeMethod (ec.Compiler, ec.CurrentType, del_type);
801 MethodBase mb = method;
802 var me = new MethodGroupExpr (new [] { mb }, del_type, loc);
803 me.InstanceExpression = InstanceExpr;
805 AParametersCollection pd = TypeManager.GetParameterData (mb);
806 int pd_count = pd.Count;
808 int arg_count = arguments == null ? 0 : arguments.Count;
810 bool params_method = pd.HasParams;
811 bool is_params_applicable = false;
812 bool is_applicable = me.IsApplicable (ec, ref arguments, arg_count, ref mb, ref is_params_applicable) == 0;
813 if (arguments != null)
814 arg_count = arguments.Count;
816 if (!is_applicable && !params_method && arg_count != pd_count) {
817 ec.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
818 TypeManager.CSharpName (del_type), arg_count.ToString ());
819 } else {
820 me.VerifyArgumentsCompat (ec, ref arguments, arg_count, mb,
821 is_params_applicable || (!is_applicable && params_method), false, loc);
824 type = TypeManager.TypeToCoreType (method.ReturnType);
825 eclass = ExprClass.Value;
826 return this;
829 public override void Emit (EmitContext ec)
832 // Invocation on delegates call the virtual Invoke member
833 // so we are always `instance' calls
835 Invocation.EmitCall (ec, false, InstanceExpr, method, arguments, loc);
838 public override void EmitStatement (EmitContext ec)
840 Emit (ec);
842 // Pop the return value if there is one
844 if (type != TypeManager.void_type)
845 ec.ig.Emit (OpCodes.Pop);
848 #if NET_4_0
849 public override System.Linq.Expressions.Expression MakeExpression (BuilderContext ctx)
851 return Invocation.MakeExpression (ctx, InstanceExpr, method, arguments);
853 #endif
855 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
857 method = storey.MutateGenericMethod (method);
858 type = storey.MutateType (type);
860 if (arguments != null)
861 arguments.MutateHoistedGenericType (storey);
863 InstanceExpr.MutateHoistedGenericType (storey);