2 // delegate.cs: Delegate Handler
5 // Ravi Pratap (ravi@ximian.com)
6 // Miguel de Icaza (miguel@ximian.com)
8 // Licensed under the terms of the GNU GPL
10 // (C) 2001 Ximian, Inc (http://www.ximian.com)
15 using System
.Collections
;
16 using System
.Reflection
;
17 using System
.Reflection
.Emit
;
20 namespace Mono
.CSharp
{
25 public class Delegate
: DeclSpace
{
26 public Expression ReturnType
;
27 public Parameters Parameters
;
29 public ConstructorBuilder ConstructorBuilder
;
30 public MethodBuilder InvokeBuilder
;
31 public MethodBuilder BeginInvokeBuilder
;
32 public MethodBuilder EndInvokeBuilder
;
37 static string[] attribute_targets
= new string [] { "type", "return" }
;
39 Expression instance_expr
;
40 MethodBase delegate_method
;
41 ReturnParameter return_attributes
;
43 const int AllowedModifiers
=
51 public Delegate (NamespaceEntry ns
, TypeContainer parent
, Expression type
,
52 int mod_flags
, MemberName name
, Parameters param_list
,
53 Attributes attrs
, Location l
)
54 : base (ns
, parent
, name
, attrs
, l
)
57 this.ReturnType
= type
;
58 ModFlags
= Modifiers
.Check (AllowedModifiers
, mod_flags
,
59 IsTopLevel
? Modifiers
.INTERNAL
:
60 Modifiers
.PRIVATE
, l
);
61 Parameters
= param_list
;
64 public override void ApplyAttributeBuilder(Attribute a
, CustomAttributeBuilder cb
)
66 if (a
.Target
== AttributeTargets
.ReturnValue
) {
67 if (return_attributes
== null)
68 return_attributes
= new ReturnParameter (InvokeBuilder
, Location
);
70 return_attributes
.ApplyAttributeBuilder (a
, cb
);
74 base.ApplyAttributeBuilder (a
, cb
);
77 public override TypeBuilder
DefineType ()
79 if (TypeBuilder
!= null)
82 ec
= new EmitContext (this, this, Location
, null, null, ModFlags
, false);
85 foreach (TypeParameter type_param
in TypeParameters
)
86 if (!type_param
.Resolve (this))
90 TypeAttributes attr
= Modifiers
.TypeAttr (ModFlags
, IsTopLevel
) |
91 TypeAttributes
.Class
| TypeAttributes
.Sealed
;
93 if (TypeManager
.multicast_delegate_type
== null)
94 Report
.Error (-100, Location
, "Internal error: delegate used before " +
95 "System.MulticastDelegate is resolved. This can only " +
96 "happen during corlib compilation, when using a delegate " +
97 "in any of the `core' classes. See bug #72015 for details.");
100 if (TypeManager
.NamespaceClash (Name
, Location
))
103 ModuleBuilder builder
= CodeGen
.Module
.Builder
;
105 TypeBuilder
= builder
.DefineType (
106 Name
, attr
, TypeManager
.multicast_delegate_type
);
108 TypeBuilder builder
= Parent
.TypeBuilder
;
110 string name
= Name
.Substring (1 + Name
.LastIndexOf ('.'));
111 TypeBuilder
= builder
.DefineNestedType (
112 name
, attr
, TypeManager
.multicast_delegate_type
);
115 TypeManager
.AddDelegateType (Name
, TypeBuilder
, this);
118 string[] param_names
= new string [TypeParameters
.Length
];
119 for (int i
= 0; i
< TypeParameters
.Length
; i
++)
120 param_names
[i
] = TypeParameters
[i
].Name
;
122 GenericTypeParameterBuilder
[] gen_params
;
123 gen_params
= TypeBuilder
.DefineGenericParameters (param_names
);
125 int offset
= CountTypeParameters
- CurrentTypeParameters
.Length
;
126 for (int i
= offset
; i
< gen_params
.Length
; i
++)
127 CurrentTypeParameters
[i
- offset
].Define (gen_params
[i
]);
129 foreach (TypeParameter type_param
in CurrentTypeParameters
) {
130 if (!type_param
.Resolve (this))
134 for (int i
= offset
; i
< gen_params
.Length
; i
++)
135 CurrentTypeParameters
[i
- offset
].DefineConstraints ();
137 TypeExpr current
= new ConstructedType (Name
, TypeParameters
, Location
);
138 current
= current
.ResolveAsTypeTerminal (ec
);
142 CurrentType
= current
.Type
;
148 public override bool DefineMembers (TypeContainer container
)
153 public override bool Define ()
155 MethodAttributes mattr
;
157 ec
= new EmitContext (this, this, Location
, null, null, ModFlags
, false);
160 foreach (TypeParameter type_param
in TypeParameters
)
161 type_param
.DefineType (ec
);
164 // FIXME: POSSIBLY make this static, as it is always constant
166 Type
[] const_arg_types
= new Type
[2];
167 const_arg_types
[0] = TypeManager
.object_type
;
168 const_arg_types
[1] = TypeManager
.intptr_type
;
170 mattr
= MethodAttributes
.RTSpecialName
| MethodAttributes
.SpecialName
|
171 MethodAttributes
.HideBySig
| MethodAttributes
.Public
;
173 ConstructorBuilder
= TypeBuilder
.DefineConstructor (mattr
,
174 CallingConventions
.Standard
,
177 ConstructorBuilder
.DefineParameter (1, ParameterAttributes
.None
, "object");
178 ConstructorBuilder
.DefineParameter (2, ParameterAttributes
.None
, "method");
180 // HACK because System.Reflection.Emit is lame
183 // FIXME: POSSIBLY make these static, as they are always the same
184 Parameter
[] fixed_pars
= new Parameter
[2];
185 fixed_pars
[0] = new Parameter (TypeManager
.system_object_expr
, "object",
186 Parameter
.Modifier
.NONE
, null);
187 fixed_pars
[1] = new Parameter (TypeManager
.system_intptr_expr
, "method",
188 Parameter
.Modifier
.NONE
, null);
189 Parameters const_parameters
= new Parameters (fixed_pars
, null, Location
);
191 TypeManager
.RegisterMethod (
193 new InternalParameters (const_arg_types
, const_parameters
),
197 ConstructorBuilder
.SetImplementationFlags (MethodImplAttributes
.Runtime
);
200 // Here the various methods like Invoke, BeginInvoke etc are defined
202 // First, call the `out of band' special method for
203 // defining recursively any types we need:
205 if (!Parameters
.ComputeAndDefineParameterTypes (ec
))
208 param_types
= Parameters
.GetParameterInfo (ec
);
209 if (param_types
== null)
216 // Check accessibility
217 foreach (Type partype
in param_types
){
218 if (!Parent
.AsAccessible (partype
, ModFlags
)) {
219 Report
.Error (59, Location
,
220 "Inconsistent accessibility: parameter type `" +
221 TypeManager
.CSharpName (partype
) + "` is less " +
222 "accessible than delegate `" + Name
+ "'");
225 if (partype
.IsPointer
&& !UnsafeOK (Parent
))
229 ReturnType
= ReturnType
.ResolveAsTypeTerminal (ec
);
230 if (ReturnType
== null)
233 ret_type
= ReturnType
.Type
;
234 if (ret_type
== null)
237 if (!Parent
.AsAccessible (ret_type
, ModFlags
)) {
238 Report
.Error (58, Location
,
239 "Inconsistent accessibility: return type `" +
240 TypeManager
.CSharpName (ret_type
) + "` is less " +
241 "accessible than delegate `" + Name
+ "'");
245 if (ret_type
.IsPointer
&& !UnsafeOK (Parent
))
249 // We don't have to check any others because they are all
250 // guaranteed to be accessible - they are standard types.
253 CallingConventions cc
= Parameters
.GetCallingConvention ();
255 mattr
= MethodAttributes
.Public
| MethodAttributes
.HideBySig
| MethodAttributes
.Virtual
;
257 InvokeBuilder
= TypeBuilder
.DefineMethod ("Invoke",
264 // Define parameters, and count out/ref parameters
268 if (Parameters
.FixedParameters
!= null){
269 int top
= Parameters
.FixedParameters
.Length
;
272 for (; i
< top
; i
++) {
273 p
= Parameters
.FixedParameters
[i
];
274 p
.DefineParameter (ec
, InvokeBuilder
, null, i
+ 1, Location
);
276 if ((p
.ModFlags
& Parameter
.Modifier
.ISBYREF
) != 0)
280 if (Parameters
.ArrayParameter
!= null){
281 Parameter p
= Parameters
.ArrayParameter
;
282 p
.DefineParameter (ec
, InvokeBuilder
, null, i
+ 1, Location
);
285 InvokeBuilder
.SetImplementationFlags (MethodImplAttributes
.Runtime
);
287 TypeManager
.RegisterMethod (InvokeBuilder
,
288 new InternalParameters (param_types
, Parameters
),
294 int params_num
= param_types
.Length
;
295 Type
[] async_param_types
= new Type
[params_num
+ 2];
297 param_types
.CopyTo (async_param_types
, 0);
299 async_param_types
[params_num
] = TypeManager
.asynccallback_type
;
300 async_param_types
[params_num
+ 1] = TypeManager
.object_type
;
302 mattr
= MethodAttributes
.Public
| MethodAttributes
.HideBySig
|
303 MethodAttributes
.Virtual
| MethodAttributes
.NewSlot
;
305 BeginInvokeBuilder
= TypeBuilder
.DefineMethod ("BeginInvoke",
308 TypeManager
.iasyncresult_type
,
312 if (Parameters
.FixedParameters
!= null){
313 int top
= Parameters
.FixedParameters
.Length
;
316 for (i
= 0 ; i
< top
; i
++) {
317 p
= Parameters
.FixedParameters
[i
];
319 p
.DefineParameter (ec
, BeginInvokeBuilder
, null, i
+ 1, Location
);
322 if (Parameters
.ArrayParameter
!= null){
323 Parameter p
= Parameters
.ArrayParameter
;
324 p
.DefineParameter (ec
, BeginInvokeBuilder
, null, i
+ 1, Location
);
329 BeginInvokeBuilder
.DefineParameter (i
+ 1, ParameterAttributes
.None
, "callback");
330 BeginInvokeBuilder
.DefineParameter (i
+ 2, ParameterAttributes
.None
, "object");
332 BeginInvokeBuilder
.SetImplementationFlags (MethodImplAttributes
.Runtime
);
334 Parameter
[] async_params
= new Parameter
[params_num
+ 2];
336 if (Parameters
.FixedParameters
!= null){
337 Parameters
.FixedParameters
.CopyTo (async_params
, 0);
338 n
= Parameters
.FixedParameters
.Length
;
340 if (Parameters
.ArrayParameter
!= null)
341 async_params
[n
] = Parameters
.ArrayParameter
;
343 async_params
[params_num
] = new Parameter (
344 TypeManager
.system_asynccallback_expr
, "callback",
345 Parameter
.Modifier
.NONE
, null);
346 async_params
[params_num
+ 1] = new Parameter (
347 TypeManager
.system_object_expr
, "object",
348 Parameter
.Modifier
.NONE
, null);
350 Parameters async_parameters
= new Parameters (async_params
, null, Location
);
351 async_parameters
.ComputeAndDefineParameterTypes (ec
);
353 TypeManager
.RegisterMethod (BeginInvokeBuilder
,
354 new InternalParameters (async_param_types
, async_parameters
),
358 // EndInvoke is a bit more interesting, all the parameters labeled as
359 // out or ref have to be duplicated here.
362 Type
[] end_param_types
= new Type
[out_params
+ 1];
363 Parameter
[] end_params
= new Parameter
[out_params
+ 1];
366 int top
= Parameters
.FixedParameters
.Length
;
367 for (i
= 0; i
< top
; i
++){
368 Parameter p
= Parameters
.FixedParameters
[i
];
369 if ((p
.ModFlags
& Parameter
.Modifier
.ISBYREF
) == 0)
372 end_param_types
[param
] = param_types
[i
];
373 end_params
[param
] = p
;
377 end_param_types
[out_params
] = TypeManager
.iasyncresult_type
;
378 end_params
[out_params
] = new Parameter (TypeManager
.system_iasyncresult_expr
, "result", Parameter
.Modifier
.NONE
, null);
381 // Create method, define parameters, register parameters with type system
383 EndInvokeBuilder
= TypeBuilder
.DefineMethod ("EndInvoke", mattr
, cc
, ret_type
, end_param_types
);
384 EndInvokeBuilder
.SetImplementationFlags (MethodImplAttributes
.Runtime
);
387 // EndInvoke: Label the parameters
389 EndInvokeBuilder
.DefineParameter (out_params
+ 1, ParameterAttributes
.None
, "result");
390 for (i
= 0; i
< end_params
.Length
-1; i
++){
391 EndInvokeBuilder
.DefineParameter (i
+ 1, end_params
[i
].Attributes
, end_params
[i
].Name
);
394 Parameters end_parameters
= new Parameters (end_params
, null, Location
);
395 end_parameters
.ComputeAndDefineParameterTypes (ec
);
397 TypeManager
.RegisterMethod (
399 new InternalParameters (end_param_types
, end_parameters
),
405 public override void Emit ()
407 if (OptAttributes
!= null) {
408 Parameters
.LabelParameters (ec
, InvokeBuilder
, Location
);
409 OptAttributes
.Emit (ec
, this);
415 public override string[] ValidAttributeTargets
{
417 return attribute_targets
;
422 protected override bool VerifyClsCompliance (DeclSpace ds
)
424 if (!base.VerifyClsCompliance (ds
)) {
428 AttributeTester
.AreParametersCompliant (Parameters
.FixedParameters
, Location
);
430 if (!AttributeTester
.IsClsCompliant (ReturnType
.Type
)) {
431 Report
.Error (3002, Location
, "Return type of '{0}' is not CLS-compliant", GetSignatureForError ());
437 // Returns the MethodBase for "Invoke" from a delegate type, this is used
438 // to extract the signature of a delegate.
440 public static MethodGroupExpr
GetInvokeMethod (EmitContext ec
, Type delegate_type
,
443 Expression ml
= Expression
.MemberLookup (
444 ec
, delegate_type
, "Invoke", loc
);
446 MethodGroupExpr mg
= ml
as MethodGroupExpr
;
448 Report
.Error (-100, loc
, "Internal error: could not find Invoke method!");
456 /// Verifies whether the method in question is compatible with the delegate
457 /// Returns the method itself if okay and null if not.
459 public static MethodBase
VerifyMethod (EmitContext ec
, Type delegate_type
, MethodBase mb
,
462 MethodGroupExpr mg
= GetInvokeMethod (ec
, delegate_type
, loc
);
466 MethodBase invoke_mb
= mg
.Methods
[0];
467 ParameterData invoke_pd
= Invocation
.GetParameterData (invoke_mb
);
469 if (!mg
.HasTypeArguments
&&
470 !TypeManager
.InferTypeArguments (ec
, invoke_pd
, ref mb
))
473 ParameterData pd
= Invocation
.GetParameterData (mb
);
474 int pd_count
= pd
.Count
;
476 if (invoke_pd
.Count
!= pd_count
)
479 for (int i
= pd_count
; i
> 0; ) {
482 Type invoke_pd_type
= invoke_pd
.ParameterType (i
);
483 Type pd_type
= pd
.ParameterType (i
);
484 Parameter
.Modifier invoke_pd_type_mod
= invoke_pd
.ParameterModifier (i
);
485 Parameter
.Modifier pd_type_mod
= pd
.ParameterModifier (i
);
487 if (invoke_pd_type
== pd_type
&&
488 invoke_pd_type_mod
== pd_type_mod
)
491 if (invoke_pd_type
.IsSubclassOf (pd_type
) &&
492 invoke_pd_type_mod
== pd_type_mod
)
493 if (RootContext
.Version
== LanguageVersion
.ISO_1
) {
494 Report
.FeatureIsNotStandardized (loc
, "contravariance");
502 Type invoke_mb_retval
= ((MethodInfo
) invoke_mb
).ReturnType
;
503 Type mb_retval
= ((MethodInfo
) mb
).ReturnType
;
504 if (invoke_mb_retval
== mb_retval
)
507 if (mb_retval
.IsSubclassOf (invoke_mb_retval
))
508 if (RootContext
.Version
== LanguageVersion
.ISO_1
) {
509 Report
.FeatureIsNotStandardized (loc
, "covariance");
519 // Verifies whether the invocation arguments are compatible with the
520 // delegate's target method
522 public static bool VerifyApplicability (EmitContext ec
, Type delegate_type
,
523 ArrayList args
, Location loc
)
530 arg_count
= args
.Count
;
532 Expression ml
= Expression
.MemberLookup (
533 ec
, delegate_type
, "Invoke", loc
);
535 if (!(ml
is MethodGroupExpr
)) {
536 Report
.Error (-100, loc
, "Internal error: could not find Invoke method!" + delegate_type
);
540 MethodBase mb
= ((MethodGroupExpr
) ml
).Methods
[0];
541 ParameterData pd
= Invocation
.GetParameterData (mb
);
543 int pd_count
= pd
.Count
;
545 bool params_method
= (pd_count
!= 0) &&
546 (pd
.ParameterModifier (pd_count
- 1) == Parameter
.Modifier
.PARAMS
);
548 if (!params_method
&& pd_count
!= arg_count
) {
549 Report
.Error (1593, loc
,
550 "Delegate '{0}' does not take {1} arguments",
551 delegate_type
.ToString (), arg_count
);
556 // Consider the case:
557 // delegate void FOO(param object[] args);
558 // FOO f = new FOO(...);
559 // f(new object[] {1, 2, 3});
561 // This should be treated like f(1,2,3). This is done by ignoring the
562 // 'param' modifier for that invocation. If that fails, then the
563 // 'param' modifier is considered.
565 // One issue is that 'VerifyArgumentsCompat' modifies the elements of
566 // the 'args' array. However, the modifications appear idempotent.
567 // Normal 'Invocation's also have the same behaviour, implicitly.
571 if (arg_count
== pd_count
)
572 ans
= Invocation
.VerifyArgumentsCompat (
573 ec
, args
, arg_count
, mb
, false,
574 delegate_type
, false, loc
);
575 if (!ans
&& params_method
)
576 ans
= Invocation
.VerifyArgumentsCompat (
577 ec
, args
, arg_count
, mb
, true,
578 delegate_type
, false, loc
);
583 /// Verifies whether the delegate in question is compatible with this one in
584 /// order to determine if instantiation from the same is possible.
586 public static bool VerifyDelegate (EmitContext ec
, Type delegate_type
, Type probe_type
, Location loc
)
588 Expression ml
= Expression
.MemberLookup (
589 ec
, delegate_type
, "Invoke", loc
);
591 if (!(ml
is MethodGroupExpr
)) {
592 Report
.Error (-100, loc
, "Internal error: could not find Invoke method!");
596 MethodBase mb
= ((MethodGroupExpr
) ml
).Methods
[0];
597 ParameterData pd
= Invocation
.GetParameterData (mb
);
599 Expression probe_ml
= Expression
.MemberLookup (
600 ec
, delegate_type
, "Invoke", loc
);
602 if (!(probe_ml
is MethodGroupExpr
)) {
603 Report
.Error (-100, loc
, "Internal error: could not find Invoke method!");
607 MethodBase probe_mb
= ((MethodGroupExpr
) probe_ml
).Methods
[0];
608 ParameterData probe_pd
= Invocation
.GetParameterData (probe_mb
);
610 if (((MethodInfo
) mb
).ReturnType
!= ((MethodInfo
) probe_mb
).ReturnType
)
613 if (pd
.Count
!= probe_pd
.Count
)
616 for (int i
= pd
.Count
; i
> 0; ) {
619 if (pd
.ParameterType (i
) != probe_pd
.ParameterType (i
) ||
620 pd
.ParameterModifier (i
) != probe_pd
.ParameterModifier (i
))
627 public static string FullDelegateDesc (Type del_type
, MethodBase mb
, ParameterData pd
)
629 StringBuilder sb
= new StringBuilder (TypeManager
.CSharpName (((MethodInfo
) mb
).ReturnType
));
631 sb
.Append (" " + del_type
.ToString ());
634 int length
= pd
.Count
;
636 for (int i
= length
; i
> 0; ) {
639 sb
.Append (pd
.ParameterDesc (length
- i
- 1));
645 return sb
.ToString ();
649 // Hack around System.Reflection as found everywhere else
650 public override MemberList
FindMembers (MemberTypes mt
, BindingFlags bf
,
651 MemberFilter filter
, object criteria
)
653 ArrayList members
= new ArrayList ();
655 if ((mt
& MemberTypes
.Method
) != 0) {
656 if (ConstructorBuilder
!= null)
657 if (filter (ConstructorBuilder
, criteria
))
658 members
.Add (ConstructorBuilder
);
660 if (InvokeBuilder
!= null)
661 if (filter (InvokeBuilder
, criteria
))
662 members
.Add (InvokeBuilder
);
664 if (BeginInvokeBuilder
!= null)
665 if (filter (BeginInvokeBuilder
, criteria
))
666 members
.Add (BeginInvokeBuilder
);
668 if (EndInvokeBuilder
!= null)
669 if (filter (EndInvokeBuilder
, criteria
))
670 members
.Add (EndInvokeBuilder
);
673 return new MemberList (members
);
676 public override MemberCache MemberCache
{
682 public Expression InstanceExpression
{
684 return instance_expr
;
687 instance_expr
= value;
691 public MethodBase TargetMethod
{
693 return delegate_method
;
696 delegate_method
= value;
700 public Type TargetReturnType
{
706 public Type
[] ParameterTypes
{
712 public override AttributeTargets AttributeTargets
{
714 return AttributeTargets
.Delegate
;
719 // Represents header string for documentation comment.
721 public override string DocCommentHeader
{
725 protected override void VerifyObsoleteAttribute()
727 CheckUsageOfObsoleteAttribute (ret_type
);
729 foreach (Type type
in param_types
) {
730 CheckUsageOfObsoleteAttribute (type
);
736 // Base class for `NewDelegate' and `ImplicitDelegateCreation'
738 public abstract class DelegateCreation
: Expression
{
739 protected MethodBase constructor_method
;
740 protected MethodBase delegate_method
;
741 protected MethodGroupExpr method_group
;
742 protected Expression delegate_instance_expression
;
744 public DelegateCreation () {}
746 public static void Error_NoMatchingMethodForDelegate (EmitContext ec
, MethodGroupExpr mg
, Type type
, Location loc
)
750 MethodBase candidate
= mg
.Methods
[0];
751 if (mg
.Methods
.Length
> 1)
752 method_desc
= candidate
.Name
;
754 method_desc
= Invocation
.FullMethodDesc (candidate
);
756 Expression invoke_method
= Expression
.MemberLookup (
757 ec
, type
, "Invoke", MemberTypes
.Method
,
758 Expression
.AllBindingFlags
, loc
);
759 MethodBase method
= ((MethodGroupExpr
) invoke_method
).Methods
[0];
760 ParameterData param
= Invocation
.GetParameterData (method
);
761 string delegate_desc
= Delegate
.FullDelegateDesc (type
, method
, param
);
763 if (!mg
.HasTypeArguments
&&
764 !TypeManager
.InferTypeArguments (ec
, param
, ref candidate
))
765 Report
.Error (411, loc
, "The type arguments for " +
766 "method `{0}' cannot be infered from " +
767 "the usage. Try specifying the type " +
768 "arguments explicitly.", method_desc
);
770 Report
.Error (123, loc
, "Method '{0}' does not " +
771 "match delegate '{1}'", method_desc
,
775 public override void Emit (EmitContext ec
)
777 if (delegate_instance_expression
== null || delegate_method
.IsStatic
)
778 ec
.ig
.Emit (OpCodes
.Ldnull
);
780 delegate_instance_expression
.Emit (ec
);
782 if (delegate_method
.IsVirtual
&& !method_group
.IsBase
) {
783 ec
.ig
.Emit (OpCodes
.Dup
);
784 ec
.ig
.Emit (OpCodes
.Ldvirtftn
, (MethodInfo
) delegate_method
);
786 ec
.ig
.Emit (OpCodes
.Ldftn
, (MethodInfo
) delegate_method
);
787 ec
.ig
.Emit (OpCodes
.Newobj
, (ConstructorInfo
) constructor_method
);
790 protected bool ResolveConstructorMethod (EmitContext ec
)
792 Expression ml
= Expression
.MemberLookup (
793 ec
, type
, ".ctor", loc
);
795 if (!(ml
is MethodGroupExpr
)) {
796 Report
.Error (-100, loc
, "Internal error: Could not find delegate constructor!");
800 constructor_method
= ((MethodGroupExpr
) ml
).Methods
[0];
804 protected Expression
ResolveMethodGroupExpr (EmitContext ec
, MethodGroupExpr mg
)
806 foreach (MethodInfo mi
in mg
.Methods
){
807 delegate_method
= Delegate
.VerifyMethod (
810 if (delegate_method
!= null)
814 if (delegate_method
== null) {
815 Error_NoMatchingMethodForDelegate (ec
, mg
, type
, loc
);
820 // Check safe/unsafe of the delegate
823 ParameterData param
= Invocation
.GetParameterData (delegate_method
);
824 int count
= param
.Count
;
826 for (int i
= 0; i
< count
; i
++){
827 if (param
.ParameterType (i
).IsPointer
){
828 Expression
.UnsafeError (loc
);
834 //TODO: implement caching when performance will be low
835 IMethodData md
= TypeManager
.GetMethod (delegate_method
);
837 if (System
.Attribute
.GetCustomAttribute (delegate_method
, TypeManager
.conditional_attribute_type
) != null) {
838 Report
.Error (1618, loc
, "Cannot create delegate with '{0}' because it has a Conditional attribute", TypeManager
.CSharpSignature (delegate_method
));
841 if (md
.OptAttributes
!= null && md
.OptAttributes
.Search (TypeManager
.conditional_attribute_type
, ec
) != null) {
842 Report
.Error (1618, loc
, "Cannot create delegate with '{0}' because it has a Conditional attribute", TypeManager
.CSharpSignature (delegate_method
));
846 if (mg
.InstanceExpression
!= null)
847 delegate_instance_expression
= mg
.InstanceExpression
.Resolve (ec
);
848 else if (ec
.IsStatic
) {
849 if (!delegate_method
.IsStatic
) {
850 Report
.Error (120, loc
,
851 "An object reference is required for the non-static method " +
852 delegate_method
.Name
);
855 delegate_instance_expression
= null;
857 delegate_instance_expression
= ec
.GetThis (loc
);
859 if (delegate_instance_expression
!= null && delegate_instance_expression
.Type
.IsValueType
)
860 delegate_instance_expression
= new BoxedCast (delegate_instance_expression
);
863 eclass
= ExprClass
.Value
;
869 // Created from the conversion code
871 public class ImplicitDelegateCreation
: DelegateCreation
{
873 ImplicitDelegateCreation (Type t
, Location l
)
879 public override Expression
DoResolve (EmitContext ec
)
884 static public Expression
Create (EmitContext ec
, MethodGroupExpr mge
, Type target_type
, Location loc
)
886 ImplicitDelegateCreation d
= new ImplicitDelegateCreation (target_type
, loc
);
887 if (d
.ResolveConstructorMethod (ec
))
888 return d
.ResolveMethodGroupExpr (ec
, mge
);
895 // A delegate-creation-expression, invoked from the `New' class
897 public class NewDelegate
: DelegateCreation
{
898 public ArrayList Arguments
;
901 // This constructor is invoked from the `New' expression
903 public NewDelegate (Type type
, ArrayList Arguments
, Location loc
)
906 this.Arguments
= Arguments
;
910 public override Expression
DoResolve (EmitContext ec
)
912 if (Arguments
== null || Arguments
.Count
!= 1) {
913 Report
.Error (149, loc
,
914 "Method name expected");
918 if (!ResolveConstructorMethod (ec
))
921 Argument a
= (Argument
) Arguments
[0];
923 if (!a
.ResolveMethodGroup (ec
, loc
))
926 Expression e
= a
.Expr
;
928 if (e
is AnonymousMethod
&& RootContext
.Version
!= LanguageVersion
.ISO_1
)
929 return ((AnonymousMethod
) e
).Compatible (ec
, type
, false);
931 MethodGroupExpr mg
= e
as MethodGroupExpr
;
933 return ResolveMethodGroupExpr (ec
, mg
);
935 Type e_type
= e
.Type
;
937 if (!TypeManager
.IsDelegateType (e_type
)) {
938 Report
.Error (149, loc
, "Method name expected");
942 method_group
= Expression
.MemberLookup (
943 ec
, type
, "Invoke", MemberTypes
.Method
,
944 Expression
.AllBindingFlags
, loc
) as MethodGroupExpr
;
946 if (method_group
== null) {
947 Report
.Error (-200, loc
, "Internal error ! Could not find Invoke method!");
951 // This is what MS' compiler reports. We could always choose
952 // to be more verbose and actually give delegate-level specifics
953 if (!Delegate
.VerifyDelegate (ec
, type
, e_type
, loc
)) {
954 Report
.Error (29, loc
, "Cannot implicitly convert type '" + e_type
+ "' " +
955 "to type '" + type
+ "'");
959 delegate_instance_expression
= e
;
960 delegate_method
= method_group
.Methods
[0];
962 eclass
= ExprClass
.Value
;
967 public class DelegateInvocation
: ExpressionStatement
{
969 public Expression InstanceExpr
;
970 public ArrayList Arguments
;
974 public DelegateInvocation (Expression instance_expr
, ArrayList args
, Location loc
)
976 this.InstanceExpr
= instance_expr
;
977 this.Arguments
= args
;
981 public override Expression
DoResolve (EmitContext ec
)
983 if (InstanceExpr
is EventExpr
) {
985 EventInfo ei
= ((EventExpr
) InstanceExpr
).EventInfo
;
987 Expression ml
= MemberLookup (
988 ec
, ec
.ContainerType
, ei
.Name
,
989 MemberTypes
.Event
, AllBindingFlags
| BindingFlags
.DeclaredOnly
, loc
);
993 // If this is the case, then the Event does not belong
994 // to this Type and so, according to the spec
995 // cannot be accessed directly
997 // Note that target will not appear as an EventExpr
998 // in the case it is being referenced within the same type container;
999 // it will appear as a FieldExpr in that case.
1002 Assign
.error70 (ei
, loc
);
1008 Type del_type
= InstanceExpr
.Type
;
1009 if (del_type
== null)
1012 if (Arguments
!= null){
1013 foreach (Argument a
in Arguments
){
1014 if (!a
.Resolve (ec
, loc
))
1019 if (!Delegate
.VerifyApplicability (ec
, del_type
, Arguments
, loc
))
1022 Expression lookup
= Expression
.MemberLookup (ec
, del_type
, "Invoke", loc
);
1023 if (!(lookup
is MethodGroupExpr
)) {
1024 Report
.Error (-100, loc
, "Internal error: could not find Invoke method!");
1028 method
= ((MethodGroupExpr
) lookup
).Methods
[0];
1029 type
= ((MethodInfo
) method
).ReturnType
;
1030 eclass
= ExprClass
.Value
;
1035 public override void Emit (EmitContext ec
)
1038 // Invocation on delegates call the virtual Invoke member
1039 // so we are always `instance' calls
1041 Invocation
.EmitCall (ec
, false, false, InstanceExpr
, method
, Arguments
, loc
);
1044 public override void EmitStatement (EmitContext ec
)
1048 // Pop the return value if there is one
1050 if (method
is MethodInfo
){
1051 if (((MethodInfo
) method
).ReturnType
!= TypeManager
.void_type
)
1052 ec
.ig
.Emit (OpCodes
.Pop
);