-//\r
-// delegate.cs: Delegate Handler\r
-//\r
-// Author: Ravi Pratap (ravi@ximian.com)\r
-//\r
-// Licensed under the terms of the GNU GPL\r
-//\r
-// (C) 2001 Ximian, Inc (http://www.ximian.com)\r
-//\r
-//\r
-\r
-using System;\r
-using System.Collections;\r
-using System.Reflection;\r
-using System.Reflection.Emit;\r
-using System.Text;\r
-\r
-namespace Mono.CSharp {\r
-\r
- /// <summary>\r
- /// Holds Delegates\r
- /// </summary>\r
- public class Delegate : DeclSpace {\r
- public readonly string ReturnType;\r
- public Parameters Parameters;\r
- public Attributes OptAttributes;\r
-\r
- public ConstructorBuilder ConstructorBuilder;\r
- public MethodBuilder InvokeBuilder;\r
- public MethodBuilder BeginInvokeBuilder;\r
- public MethodBuilder EndInvokeBuilder;\r
- \r
- Type [] param_types;\r
- Type ret_type;\r
- \r
- Expression instance_expr;\r
- MethodBase delegate_method;\r
- \r
- const int AllowedModifiers =\r
- Modifiers.NEW |\r
- Modifiers.PUBLIC |\r
- Modifiers.PROTECTED |\r
- Modifiers.INTERNAL |\r
- Modifiers.UNSAFE |\r
- Modifiers.PRIVATE;\r
-\r
- public Delegate (TypeContainer parent, string type, int mod_flags,\r
- string name, Parameters param_list,\r
- Attributes attrs, Location l)\r
- : base (parent, name, l)\r
- {\r
- this.ReturnType = type;\r
- ModFlags = Modifiers.Check (AllowedModifiers, mod_flags, Modifiers.PUBLIC, l);\r
- Parameters = param_list;\r
- OptAttributes = attrs;\r
- }\r
-\r
- public override TypeBuilder DefineType ()\r
- {\r
- TypeAttributes attr;\r
-\r
- if (TypeBuilder != null)\r
- return TypeBuilder;\r
- \r
- if (IsTopLevel) {\r
- ModuleBuilder builder = CodeGen.ModuleBuilder;\r
- attr = TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Sealed;\r
-\r
- TypeBuilder = builder.DefineType (\r
- Name, attr, TypeManager.multicast_delegate_type);\r
- } else {\r
- TypeBuilder builder = Parent.TypeBuilder;\r
- attr = TypeAttributes.NestedPublic | TypeAttributes.Class |\r
- TypeAttributes.Sealed;\r
-\r
- string name = Name.Substring (1 + Name.LastIndexOf ('.'));\r
- TypeBuilder = builder.DefineNestedType (\r
- name, attr, TypeManager.multicast_delegate_type);\r
- }\r
-\r
- TypeManager.AddDelegateType (Name, TypeBuilder, this);\r
-\r
- return TypeBuilder;\r
- }\r
-\r
- public override bool Define (TypeContainer parent)\r
- {\r
- MethodAttributes mattr;\r
- int i;\r
-\r
- // FIXME: POSSIBLY make this static, as it is always constant\r
- //\r
- Type [] const_arg_types = new Type [2];\r
- const_arg_types [0] = TypeManager.object_type;\r
- const_arg_types [1] = TypeManager.intptr_type;\r
-\r
- mattr = MethodAttributes.RTSpecialName | MethodAttributes.SpecialName |\r
- MethodAttributes.HideBySig | MethodAttributes.Public;\r
-\r
- ConstructorBuilder = TypeBuilder.DefineConstructor (mattr,\r
- CallingConventions.Standard,\r
- const_arg_types);\r
-\r
- ConstructorBuilder.DefineParameter (1, ParameterAttributes.None, "object");\r
- ConstructorBuilder.DefineParameter (2, ParameterAttributes.None, "method");\r
- //\r
- // HACK because System.Reflection.Emit is lame\r
- //\r
- //\r
- // FIXME: POSSIBLY make these static, as they are always the same\r
- Parameter [] fixed_pars = new Parameter [2];\r
- fixed_pars [0] = new Parameter (null, null, Parameter.Modifier.NONE, null);\r
- fixed_pars [1] = new Parameter (null, null, Parameter.Modifier.NONE, null);\r
- Parameters const_parameters = new Parameters (fixed_pars, null, Location);\r
- \r
- TypeManager.RegisterMethod (\r
- ConstructorBuilder,\r
- new InternalParameters (const_arg_types, const_parameters),\r
- const_arg_types);\r
- \r
- \r
- ConstructorBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);\r
-\r
- //\r
- // Here the various methods like Invoke, BeginInvoke etc are defined\r
- //\r
- // First, call the `out of band' special method for\r
- // defining recursively any types we need:\r
- \r
- if (!Parameters.ComputeAndDefineParameterTypes (this))\r
- return false;\r
- \r
- param_types = Parameters.GetParameterInfo (this);\r
- if (param_types == null)\r
- return false;\r
-\r
- //\r
- // Invoke method\r
- //\r
- \r
- // Check accessibility\r
- foreach (Type partype in param_types)\r
- if (!TypeContainer.AsAccessible (partype, ModFlags))\r
- return false;\r
- \r
- ret_type = FindType (ReturnType);\r
- if (ret_type == null)\r
- return false;\r
-\r
- if (!TypeContainer.AsAccessible (ret_type, ModFlags))\r
- return false;\r
-\r
- //\r
- // We don't have to check any others because they are all\r
- // guaranteed to be accessible - they are standard types.\r
- //\r
- \r
- CallingConventions cc = Parameters.GetCallingConvention ();\r
-\r
- mattr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual;\r
-\r
- InvokeBuilder = TypeBuilder.DefineMethod ("Invoke", \r
- mattr, \r
- cc,\r
- ret_type, \r
- param_types);\r
-\r
- i = 0;\r
- if (Parameters.FixedParameters != null){\r
- int top = Parameters.FixedParameters.Length;\r
- Parameter p;\r
- \r
- for (; i < top; i++) {\r
- p = Parameters.FixedParameters [i];\r
-\r
- InvokeBuilder.DefineParameter (\r
- i+1, p.Attributes, p.Name);\r
- }\r
- }\r
- if (Parameters.ArrayParameter != null){\r
- Parameter p = Parameters.ArrayParameter;\r
- \r
- InvokeBuilder.DefineParameter (\r
- i+1, p.Attributes, p.Name);\r
- }\r
- \r
- InvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);\r
-\r
- TypeManager.RegisterMethod (InvokeBuilder,\r
- new InternalParameters (parent, Parameters),\r
- param_types);\r
-\r
- //\r
- // BeginInvoke\r
- //\r
- int params_num = param_types.Length;\r
- Type [] async_param_types = new Type [params_num + 2];\r
-\r
- param_types.CopyTo (async_param_types, 0);\r
-\r
- async_param_types [params_num] = TypeManager.asynccallback_type;\r
- async_param_types [params_num + 1] = TypeManager.object_type;\r
-\r
- mattr = MethodAttributes.Public | MethodAttributes.HideBySig |\r
- MethodAttributes.Virtual | MethodAttributes.NewSlot;\r
- \r
- BeginInvokeBuilder = TypeBuilder.DefineMethod ("BeginInvoke",\r
- mattr,\r
- cc,\r
- TypeManager.iasyncresult_type,\r
- async_param_types);\r
-\r
- i = 0;\r
- if (Parameters.FixedParameters != null){\r
- int top = Parameters.FixedParameters.Length;\r
- Parameter p;\r
- \r
- for (i = 0 ; i < top; i++) {\r
- p = Parameters.FixedParameters [i];\r
-\r
- BeginInvokeBuilder.DefineParameter (\r
- i+1, p.Attributes, p.Name);\r
- }\r
- }\r
- if (Parameters.ArrayParameter != null){\r
- Parameter p = Parameters.ArrayParameter;\r
- \r
- BeginInvokeBuilder.DefineParameter (\r
- i+1, p.Attributes, p.Name);\r
- i++;\r
- }\r
-\r
- BeginInvokeBuilder.DefineParameter (i + 1, ParameterAttributes.None, "callback");\r
- BeginInvokeBuilder.DefineParameter (i + 2, ParameterAttributes.None, "object");\r
- \r
- BeginInvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);\r
-\r
- Parameter [] async_params = new Parameter [params_num + 2];\r
- int n = 0;\r
- if (Parameters.FixedParameters != null){\r
- Parameters.FixedParameters.CopyTo (async_params, 0);\r
- n = Parameters.FixedParameters.Length;\r
- }\r
- if (Parameters.ArrayParameter != null)\r
- async_params [n] = Parameters.ArrayParameter;\r
- \r
- async_params [params_num] = new Parameter ("System.AsyncCallback", "callback",\r
- Parameter.Modifier.NONE, null);\r
- async_params [params_num + 1] = new Parameter ("System.Object", "object",\r
- Parameter.Modifier.NONE, null);\r
-\r
- Parameters async_parameters = new Parameters (async_params, null, Location);\r
- \r
- async_parameters.ComputeAndDefineParameterTypes (this);\r
- TypeManager.RegisterMethod (BeginInvokeBuilder,\r
- new InternalParameters (parent, async_parameters),\r
- async_param_types);\r
-\r
- //\r
- // EndInvoke\r
- //\r
- Type [] end_param_types = new Type [1];\r
- end_param_types [0] = TypeManager.iasyncresult_type;\r
- \r
- EndInvokeBuilder = TypeBuilder.DefineMethod ("EndInvoke",\r
- mattr,\r
- cc,\r
- ret_type,\r
- end_param_types);\r
- EndInvokeBuilder.DefineParameter (1, ParameterAttributes.None, "result");\r
- \r
- EndInvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);\r
-\r
- Parameter [] end_params = new Parameter [1];\r
- end_params [0] = new Parameter ("System.IAsyncResult", "result",\r
- Parameter.Modifier.NONE, null);\r
-\r
- TypeManager.RegisterMethod (EndInvokeBuilder,\r
- new InternalParameters (\r
- parent,\r
- new Parameters (end_params, null, Location)),\r
- end_param_types);\r
-\r
- return true;\r
- }\r
-\r
- /// <summary>\r
- /// Verifies whether the method in question is compatible with the delegate\r
- /// Returns the method itself if okay and null if not.\r
- /// </summary>\r
- public static MethodBase VerifyMethod (EmitContext ec, Type delegate_type, MethodBase mb,\r
- Location loc)\r
- {\r
- ParameterData pd = Invocation.GetParameterData (mb);\r
-\r
- int pd_count = pd.Count;\r
-\r
- Expression ml = Expression.MemberLookup (\r
- ec, delegate_type, "Invoke", loc);\r
-\r
- if (!(ml is MethodGroupExpr)) {\r
- Report.Error (-100, loc, "Internal error : could not find Invoke method!");\r
- return null;\r
- }\r
-\r
- MethodBase invoke_mb = ((MethodGroupExpr) ml).Methods [0];\r
-\r
- ParameterData invoke_pd = Invocation.GetParameterData (invoke_mb);\r
-\r
- if (invoke_pd.Count != pd_count)\r
- return null;\r
-\r
- bool mismatch = false;\r
- for (int i = pd_count; i > 0; ) {\r
- i--;\r
-\r
- if (invoke_pd.ParameterType (i) == pd.ParameterType (i))\r
- continue;\r
- else {\r
- mismatch = true;\r
- break;\r
- }\r
- }\r
-\r
- if (mismatch) {\r
- Report.Error (\r
- 123, loc, "Method '" + Invocation.FullMethodDesc (mb) +\r
- "' does not match delegate '" +\r
- FullDelegateDesc (delegate_type, invoke_mb, invoke_pd) + "'");\r
- return null;\r
- }\r
-\r
- if (((MethodInfo) invoke_mb).ReturnType == ((MethodInfo) mb).ReturnType)\r
- return mb;\r
- else\r
- mismatch = true;\r
-\r
- if (mismatch) {\r
- Report.Error (123, loc, "Method '" + Invocation.FullMethodDesc (mb) +\r
- "' does not match delegate '" +\r
- FullDelegateDesc (delegate_type, invoke_mb, invoke_pd) + "'");\r
- return null;\r
- }\r
-\r
- return null;\r
- }\r
-\r
- // <summary>\r
- // Verifies whether the invocation arguments are compatible with the\r
- // delegate's target method\r
- // </summary>\r
- public static bool VerifyApplicability (EmitContext ec,\r
- Type delegate_type,\r
- ArrayList args,\r
- Location loc)\r
- {\r
- int arg_count;\r
-\r
- if (args == null)\r
- arg_count = 0;\r
- else\r
- arg_count = args.Count;\r
-\r
- Expression ml = Expression.MemberLookup (\r
- ec, delegate_type, "Invoke", loc);\r
- \r
- if (!(ml is MethodGroupExpr)) {\r
- Report.Error (-100, loc, "Internal error : could not find Invoke method!");\r
- return false;\r
- }\r
- \r
- MethodBase mb = ((MethodGroupExpr) ml).Methods [0];\r
- ParameterData pd = Invocation.GetParameterData (mb);\r
-\r
- int pd_count = pd.Count;\r
-\r
- bool not_params_method = (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS);\r
-\r
- if (not_params_method && pd_count != arg_count) {\r
- Report.Error (1593, loc,\r
- "Delegate '" + delegate_type.ToString ()\r
- + "' does not take '" + arg_count + "' arguments");\r
- return false;\r
- }\r
-\r
- return Invocation.VerifyArgumentsCompat (ec, args, arg_count, mb, !not_params_method,\r
- delegate_type, loc);\r
- }\r
- \r
- /// <summary>\r
- /// Verifies whether the delegate in question is compatible with this one in\r
- /// order to determine if instantiation from the same is possible.\r
- /// </summary>\r
- public static bool VerifyDelegate (EmitContext ec, Type delegate_type, Type probe_type, Location loc)\r
- {\r
- Expression ml = Expression.MemberLookup (\r
- ec, delegate_type, "Invoke", loc);\r
- \r
- if (!(ml is MethodGroupExpr)) {\r
- Report.Error (-100, loc, "Internal error : could not find Invoke method!");\r
- return false;\r
- }\r
- \r
- MethodBase mb = ((MethodGroupExpr) ml).Methods [0];\r
- ParameterData pd = Invocation.GetParameterData (mb);\r
-\r
- Expression probe_ml = Expression.MemberLookup (\r
- ec, delegate_type, "Invoke", loc);\r
- \r
- if (!(probe_ml is MethodGroupExpr)) {\r
- Report.Error (-100, loc, "Internal error : could not find Invoke method!");\r
- return false;\r
- }\r
- \r
- MethodBase probe_mb = ((MethodGroupExpr) probe_ml).Methods [0];\r
- ParameterData probe_pd = Invocation.GetParameterData (probe_mb);\r
- \r
- if (((MethodInfo) mb).ReturnType != ((MethodInfo) probe_mb).ReturnType)\r
- return false;\r
-\r
- if (pd.Count != probe_pd.Count)\r
- return false;\r
-\r
- for (int i = pd.Count; i > 0; ) {\r
- i--;\r
-\r
- if (pd.ParameterType (i) != probe_pd.ParameterType (i) ||\r
- pd.ParameterModifier (i) != probe_pd.ParameterModifier (i))\r
- return false;\r
- }\r
- \r
- return true;\r
- }\r
- \r
- public static string FullDelegateDesc (Type del_type, MethodBase mb, ParameterData pd)\r
- {\r
- StringBuilder sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));\r
- \r
- sb.Append (" " + del_type.ToString ());\r
- sb.Append (" (");\r
-\r
- int length = pd.Count;\r
- \r
- for (int i = length; i > 0; ) {\r
- i--;\r
- \r
- sb.Append (TypeManager.CSharpName (pd.ParameterType (length - i - 1)));\r
- if (i != 0)\r
- sb.Append (", ");\r
- }\r
- \r
- sb.Append (")");\r
- return sb.ToString ();\r
- \r
- }\r
- \r
- // Hack around System.Reflection as found everywhere else\r
- public MemberInfo [] FindMembers (MemberTypes mt, BindingFlags bf, MemberFilter filter, object criteria)\r
- {\r
- ArrayList members = new ArrayList ();\r
-\r
- if ((mt & MemberTypes.Method) != 0) {\r
- if (filter (ConstructorBuilder, criteria))\r
- members.Add (ConstructorBuilder);\r
-\r
- if (filter (InvokeBuilder, criteria))\r
- members.Add (InvokeBuilder);\r
-\r
- if (filter (BeginInvokeBuilder, criteria))\r
- members.Add (BeginInvokeBuilder);\r
-\r
- if (filter (EndInvokeBuilder, criteria))\r
- members.Add (EndInvokeBuilder);\r
- }\r
-\r
- int count = members.Count;\r
-\r
- if (count > 0) {\r
- MemberInfo [] mi = new MemberInfo [count];\r
- members.CopyTo (mi, 0);\r
- return mi;\r
- }\r
-\r
- return null;\r
- }\r
- \r
- public void CloseDelegate ()\r
- {\r
- TypeBuilder.CreateType ();\r
- }\r
- \r
- public Expression InstanceExpression {\r
- get {\r
- return instance_expr;\r
- }\r
- set {\r
- instance_expr = value;\r
- }\r
- }\r
-\r
- public MethodBase TargetMethod {\r
- get {\r
- return delegate_method;\r
- }\r
- set {\r
- delegate_method = value;\r
- }\r
- }\r
-\r
- public Type TargetReturnType {\r
- get {\r
- return ret_type;\r
- }\r
- }\r
-\r
- public Type [] ParameterTypes {\r
- get {\r
- return param_types;\r
- }\r
- }\r
- \r
- }\r
-\r
- public class NewDelegate : Expression {\r
-\r
- public ArrayList Arguments;\r
-\r
- MethodBase constructor_method;\r
- MethodBase delegate_method;\r
- Expression delegate_instance_expr;\r
-\r
- Location Location;\r
- \r
- public NewDelegate (Type type, ArrayList Arguments, Location loc)\r
- {\r
- this.type = type;\r
- this.Arguments = Arguments;\r
- this.Location = loc; \r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- if (Arguments == null) {\r
- Report.Error (-11, Location,\r
- "Delegate creation expression takes only one argument");\r
- return null;\r
- }\r
-\r
- if (Arguments.Count != 1) {\r
- Report.Error (-11, Location,\r
- "Delegate creation expression takes only one argument");\r
- return null;\r
- }\r
-\r
- Expression ml = Expression.MemberLookup (\r
- ec, type, ".ctor", Location);\r
-\r
- if (!(ml is MethodGroupExpr)) {\r
- Report.Error (-100, Location, "Internal error : Could not find delegate constructor!");\r
- return null;\r
- }\r
-\r
- constructor_method = ((MethodGroupExpr) ml).Methods [0];\r
- Argument a = (Argument) Arguments [0];\r
- \r
- if (!a.Resolve (ec, Location))\r
- return null;\r
- \r
- Expression e = a.Expr;\r
-\r
- if (e is MethodGroupExpr) {\r
- MethodGroupExpr mg = (MethodGroupExpr) e;\r
-\r
- foreach (MethodInfo mi in mg.Methods){\r
- delegate_method = Delegate.VerifyMethod (ec, type, mi, Location);\r
-\r
- if (delegate_method != null)\r
- break;\r
- }\r
- \r
- if (delegate_method == null) {\r
- Report.Error (-14, Location, "Ambiguous method reference in delegate creation");\r
- return null;\r
- }\r
- \r
- if (mg.InstanceExpression != null)\r
- delegate_instance_expr = mg.InstanceExpression.Resolve (ec);\r
- else {\r
- if (!ec.IsStatic)\r
- delegate_instance_expr = ec.This;\r
- else\r
- delegate_instance_expr = null;\r
- }\r
-\r
- if (delegate_instance_expr != null)\r
- if (delegate_instance_expr.Type.IsValueType)\r
- delegate_instance_expr = new BoxedCast (delegate_instance_expr);\r
- \r
- eclass = ExprClass.Value;\r
- return this;\r
- }\r
-\r
- Type e_type = e.Type;\r
-\r
- if (!TypeManager.IsDelegateType (e_type)) {\r
- Report.Error (-12, Location, "Cannot create a delegate from something " +\r
- "not a delegate or a method.");\r
- return null;\r
- }\r
-\r
- // This is what MS' compiler reports. We could always choose\r
- // to be more verbose and actually give delegate-level specifics\r
- \r
- if (!Delegate.VerifyDelegate (ec, type, e_type, Location)) {\r
- Report.Error (29, Location, "Cannot implicitly convert type '" + e_type + "' " +\r
- "to type '" + type + "'");\r
- return null;\r
- }\r
-\r
- Expression invoke_method = Expression.MemberLookup (\r
- ec, e_type, "Invoke", MemberTypes.Method,\r
- Expression.AllBindingFlags, Location);\r
-\r
- if (invoke_method == null) {\r
- Report.Error (-200, Location, "Internal error ! COuld not find Invoke method!");\r
- return null;\r
- }\r
- \r
- delegate_instance_expr = e;\r
- delegate_method = ((MethodGroupExpr) invoke_method).Methods [0];\r
- \r
- eclass = ExprClass.Value;\r
- return this;\r
- }\r
- \r
- public override void Emit (EmitContext ec)\r
- {\r
- if (delegate_instance_expr == null ||\r
- delegate_method.IsStatic)\r
- ec.ig.Emit (OpCodes.Ldnull);\r
- else\r
- delegate_instance_expr.Emit (ec);\r
- \r
- ec.ig.Emit (OpCodes.Ldftn, (MethodInfo) delegate_method);\r
- ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) constructor_method);\r
- }\r
- }\r
-\r
- public class DelegateInvocation : ExpressionStatement {\r
-\r
- public Expression InstanceExpr;\r
- public ArrayList Arguments;\r
- public Location Location;\r
-\r
- MethodBase method;\r
- \r
- public DelegateInvocation (Expression instance_expr, ArrayList args, Location loc)\r
- {\r
- this.InstanceExpr = instance_expr;\r
- this.Arguments = args;\r
- this.Location = loc;\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- Type del_type = InstanceExpr.Type;\r
- if (del_type == null)\r
- return null;\r
- \r
- if (Arguments != null){\r
- foreach (Argument a in Arguments){\r
- if (!a.Resolve (ec, Location))\r
- return null;\r
- }\r
- }\r
- \r
- if (!Delegate.VerifyApplicability (ec, del_type, Arguments, Location))\r
- return null;\r
-\r
- Expression ml = Expression.MemberLookup (ec, del_type, "Invoke", Location);\r
- if (!(ml is MethodGroupExpr)) {\r
- Report.Error (-100, Location, "Internal error : could not find Invoke method!");\r
- return null;\r
- }\r
- \r
- method = ((MethodGroupExpr) ml).Methods [0];\r
- type = ((MethodInfo) method).ReturnType;\r
- eclass = ExprClass.Value;\r
- \r
- return this;\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- Delegate del = TypeManager.LookupDelegate (InstanceExpr.Type);\r
-\r
- //\r
- // Invocation on delegates call the virtual Invoke member\r
- // so we are always `instance' calls\r
- //\r
- Invocation.EmitCall (ec, false, false, InstanceExpr, method, Arguments, Location);\r
- }\r
-\r
- public override void EmitStatement (EmitContext ec)\r
- {\r
- Emit (ec);\r
- // \r
- // Pop the return value if there is one\r
- //\r
- if (method is MethodInfo){\r
- if (((MethodInfo) method).ReturnType != TypeManager.void_type)\r
- ec.ig.Emit (OpCodes.Pop);\r
- }\r
- }\r
-\r
- }\r
-}\r
+//
+// delegate.cs: Delegate Handler
+//
+// Authors:
+// Ravi Pratap (ravi@ximian.com)
+// Miguel de Icaza (miguel@ximian.com)
+//
+// Licensed under the terms of the GNU GPL
+//
+// (C) 2001 Ximian, Inc (http://www.ximian.com)
+//
+//
+
+using System;
+using System.Collections;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Text;
+
+namespace Mono.CSharp {
+
+ /// <summary>
+ /// Holds Delegates
+ /// </summary>
+ public class Delegate : DeclSpace {
+ public Expression ReturnType;
+ public Parameters Parameters;
+
+ public ConstructorBuilder ConstructorBuilder;
+ public MethodBuilder InvokeBuilder;
+ public MethodBuilder BeginInvokeBuilder;
+ public MethodBuilder EndInvokeBuilder;
+
+ Type [] param_types;
+ Type ret_type;
+
+ static string[] attribute_targets = new string [] { "type", "return" };
+
+ Expression instance_expr;
+ MethodBase delegate_method;
+ ReturnParameter return_attributes;
+
+ const int AllowedModifiers =
+ Modifiers.NEW |
+ Modifiers.PUBLIC |
+ Modifiers.PROTECTED |
+ Modifiers.INTERNAL |
+ Modifiers.UNSAFE |
+ Modifiers.PRIVATE;
+
+ public Delegate (NamespaceEntry ns, TypeContainer parent, Expression type,
+ int mod_flags, string name, Parameters param_list,
+ Attributes attrs, Location l)
+ : base (ns, parent, name, attrs, l)
+
+ {
+ this.ReturnType = type;
+ ModFlags = Modifiers.Check (AllowedModifiers, mod_flags,
+ IsTopLevel ? Modifiers.INTERNAL :
+ Modifiers.PRIVATE, l);
+ Parameters = param_list;
+ }
+
+ public override void ApplyAttributeBuilder(Attribute a, CustomAttributeBuilder cb)
+ {
+ if (a.Target == "return") {
+ if (return_attributes == null)
+ return_attributes = new ReturnParameter (InvokeBuilder, Location);
+
+ return_attributes.ApplyAttributeBuilder (a, cb);
+ return;
+ }
+
+ base.ApplyAttributeBuilder (a, cb);
+ }
+
+ public override TypeBuilder DefineType ()
+ {
+ if (TypeBuilder != null)
+ return TypeBuilder;
+
+ TypeAttributes attr = Modifiers.TypeAttr (ModFlags, IsTopLevel) |
+ TypeAttributes.Class | TypeAttributes.Sealed;
+
+ if (IsTopLevel) {
+ if (TypeManager.NamespaceClash (Name, Location))
+ return null;
+
+ ModuleBuilder builder = CodeGen.Module.Builder;
+
+ TypeBuilder = builder.DefineType (
+ Name, attr, TypeManager.multicast_delegate_type);
+ } else {
+ TypeBuilder builder = Parent.TypeBuilder;
+
+ string name = Name.Substring (1 + Name.LastIndexOf ('.'));
+ TypeBuilder = builder.DefineNestedType (
+ name, attr, TypeManager.multicast_delegate_type);
+ }
+
+ TypeManager.AddDelegateType (Name, TypeBuilder, this);
+
+ return TypeBuilder;
+ }
+
+ public override bool DefineMembers (TypeContainer container)
+ {
+ return true;
+ }
+
+ public override bool Define (TypeContainer container)
+ {
+ MethodAttributes mattr;
+ int i;
+ EmitContext ec = new EmitContext (this, this, Location, null,
+ null, ModFlags, false);
+
+ // FIXME: POSSIBLY make this static, as it is always constant
+ //
+ Type [] const_arg_types = new Type [2];
+ const_arg_types [0] = TypeManager.object_type;
+ const_arg_types [1] = TypeManager.intptr_type;
+
+ mattr = MethodAttributes.RTSpecialName | MethodAttributes.SpecialName |
+ MethodAttributes.HideBySig | MethodAttributes.Public;
+
+ ConstructorBuilder = TypeBuilder.DefineConstructor (mattr,
+ CallingConventions.Standard,
+ const_arg_types);
+
+ ConstructorBuilder.DefineParameter (1, ParameterAttributes.None, "object");
+ ConstructorBuilder.DefineParameter (2, ParameterAttributes.None, "method");
+ //
+ // HACK because System.Reflection.Emit is lame
+ //
+ //
+ // FIXME: POSSIBLY make these static, as they are always the same
+ Parameter [] fixed_pars = new Parameter [2];
+ fixed_pars [0] = new Parameter (null, null, Parameter.Modifier.NONE, null);
+ fixed_pars [1] = new Parameter (null, null, Parameter.Modifier.NONE, null);
+ Parameters const_parameters = new Parameters (fixed_pars, null, Location);
+
+ TypeManager.RegisterMethod (
+ ConstructorBuilder,
+ new InternalParameters (const_arg_types, const_parameters),
+ const_arg_types);
+
+
+ ConstructorBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);
+
+ //
+ // Here the various methods like Invoke, BeginInvoke etc are defined
+ //
+ // First, call the `out of band' special method for
+ // defining recursively any types we need:
+
+ if (!Parameters.ComputeAndDefineParameterTypes (this))
+ return false;
+
+ param_types = Parameters.GetParameterInfo (this);
+ if (param_types == null)
+ return false;
+
+ //
+ // Invoke method
+ //
+
+ // Check accessibility
+ foreach (Type partype in param_types){
+ if (!container.AsAccessible (partype, ModFlags)) {
+ Report.Error (59, Location,
+ "Inconsistent accessibility: parameter type `" +
+ TypeManager.CSharpName (partype) + "` is less " +
+ "accessible than delegate `" + Name + "'");
+ return false;
+ }
+ if (partype.IsPointer && !UnsafeOK (container))
+ return false;
+ }
+
+ ReturnType = ResolveTypeExpr (ReturnType, false, Location);
+ if (ReturnType == null)
+ return false;
+
+ ret_type = ReturnType.Type;
+ if (ret_type == null)
+ return false;
+
+ if (!container.AsAccessible (ret_type, ModFlags)) {
+ Report.Error (58, Location,
+ "Inconsistent accessibility: return type `" +
+ TypeManager.CSharpName (ret_type) + "` is less " +
+ "accessible than delegate `" + Name + "'");
+ return false;
+ }
+
+ if (ret_type.IsPointer && !UnsafeOK (container))
+ return false;
+
+ //
+ // We don't have to check any others because they are all
+ // guaranteed to be accessible - they are standard types.
+ //
+
+ CallingConventions cc = Parameters.GetCallingConvention ();
+
+ mattr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual;
+
+ InvokeBuilder = TypeBuilder.DefineMethod ("Invoke",
+ mattr,
+ cc,
+ ret_type,
+ param_types);
+
+ //
+ // Define parameters, and count out/ref parameters
+ //
+ int out_params = 0;
+ i = 0;
+ if (Parameters.FixedParameters != null){
+ int top = Parameters.FixedParameters.Length;
+ Parameter p;
+
+ for (; i < top; i++) {
+ p = Parameters.FixedParameters [i];
+ p.DefineParameter (ec, InvokeBuilder, null, i + 1, Location);
+
+ if ((p.ModFlags & Parameter.Modifier.ISBYREF) != 0)
+ out_params++;
+ }
+ }
+ if (Parameters.ArrayParameter != null){
+ Parameter p = Parameters.ArrayParameter;
+ p.DefineParameter (ec, InvokeBuilder, null, i + 1, Location);
+ }
+
+ InvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);
+
+ TypeManager.RegisterMethod (InvokeBuilder,
+ new InternalParameters (container, Parameters),
+ param_types);
+
+ //
+ // BeginInvoke
+ //
+ int params_num = param_types.Length;
+ Type [] async_param_types = new Type [params_num + 2];
+
+ param_types.CopyTo (async_param_types, 0);
+
+ async_param_types [params_num] = TypeManager.asynccallback_type;
+ async_param_types [params_num + 1] = TypeManager.object_type;
+
+ mattr = MethodAttributes.Public | MethodAttributes.HideBySig |
+ MethodAttributes.Virtual | MethodAttributes.NewSlot;
+
+ BeginInvokeBuilder = TypeBuilder.DefineMethod ("BeginInvoke",
+ mattr,
+ cc,
+ TypeManager.iasyncresult_type,
+ async_param_types);
+
+ i = 0;
+ if (Parameters.FixedParameters != null){
+ int top = Parameters.FixedParameters.Length;
+ Parameter p;
+
+ for (i = 0 ; i < top; i++) {
+ p = Parameters.FixedParameters [i];
+
+ p.DefineParameter (ec, BeginInvokeBuilder, null, i + 1, Location);
+ }
+ }
+ if (Parameters.ArrayParameter != null){
+ Parameter p = Parameters.ArrayParameter;
+ p.DefineParameter (ec, BeginInvokeBuilder, null, i + 1, Location);
+
+ i++;
+ }
+
+ BeginInvokeBuilder.DefineParameter (i + 1, ParameterAttributes.None, "callback");
+ BeginInvokeBuilder.DefineParameter (i + 2, ParameterAttributes.None, "object");
+
+ BeginInvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);
+
+ Parameter [] async_params = new Parameter [params_num + 2];
+ int n = 0;
+ if (Parameters.FixedParameters != null){
+ Parameters.FixedParameters.CopyTo (async_params, 0);
+ n = Parameters.FixedParameters.Length;
+ }
+ if (Parameters.ArrayParameter != null)
+ async_params [n] = Parameters.ArrayParameter;
+
+ async_params [params_num] = new Parameter (
+ TypeManager.system_asynccallback_expr, "callback",
+ Parameter.Modifier.NONE, null);
+ async_params [params_num + 1] = new Parameter (
+ TypeManager.system_object_expr, "object",
+ Parameter.Modifier.NONE, null);
+
+ Parameters async_parameters = new Parameters (async_params, null, Location);
+ async_parameters.ComputeAndDefineParameterTypes (this);
+
+ async_parameters.ComputeAndDefineParameterTypes (this);
+ TypeManager.RegisterMethod (BeginInvokeBuilder,
+ new InternalParameters (container, async_parameters),
+ async_param_types);
+
+ //
+ // EndInvoke is a bit more interesting, all the parameters labeled as
+ // out or ref have to be duplicated here.
+ //
+
+ Type [] end_param_types = new Type [out_params + 1];
+ Parameter [] end_params = new Parameter [out_params + 1];
+ int param = 0;
+ if (out_params > 0){
+ int top = Parameters.FixedParameters.Length;
+ for (i = 0; i < top; i++){
+ Parameter p = Parameters.FixedParameters [i];
+ if ((p.ModFlags & Parameter.Modifier.ISBYREF) == 0)
+ continue;
+
+ end_param_types [param] = param_types [i];
+ end_params [param] = p;
+ param++;
+ }
+ }
+ end_param_types [out_params] = TypeManager.iasyncresult_type;
+ end_params [out_params] = new Parameter (TypeManager.system_iasyncresult_expr, "result", Parameter.Modifier.NONE, null);
+
+ //
+ // Create method, define parameters, register parameters with type system
+ //
+ EndInvokeBuilder = TypeBuilder.DefineMethod ("EndInvoke", mattr, cc, ret_type, end_param_types);
+ EndInvokeBuilder.SetImplementationFlags (MethodImplAttributes.Runtime);
+
+ //
+ // EndInvoke: Label the parameters
+ //
+ EndInvokeBuilder.DefineParameter (out_params + 1, ParameterAttributes.None, "result");
+ for (i = 0; i < end_params.Length-1; i++){
+ EndInvokeBuilder.DefineParameter (i + 1, end_params [i].Attributes, end_params [i].Name);
+ }
+
+ Parameters end_parameters = new Parameters (end_params, null, Location);
+ end_parameters.ComputeAndDefineParameterTypes (this);
+
+ TypeManager.RegisterMethod (
+ EndInvokeBuilder,
+ new InternalParameters (container, end_parameters),
+ end_param_types);
+
+ return true;
+ }
+
+ public override void Emit (TypeContainer tc)
+ {
+ if (OptAttributes != null) {
+ EmitContext ec = new EmitContext (tc, this, Location, null, null, ModFlags, false);
+ Parameters.LabelParameters (ec, InvokeBuilder, Location);
+ OptAttributes.Emit (ec, this);
+ }
+
+ base.Emit (tc);
+ }
+
+ protected override string[] ValidAttributeTargets {
+ get {
+ return attribute_targets;
+ }
+ }
+
+ //TODO: duplicate
+ protected override bool VerifyClsCompliance (DeclSpace ds)
+ {
+ if (!base.VerifyClsCompliance (ds)) {
+ return false;
+ }
+
+ AttributeTester.AreParametersCompliant (Parameters.FixedParameters, Location);
+
+ if (!AttributeTester.IsClsCompliant (ReturnType.Type)) {
+ Report.Error_T (3002, Location, GetSignatureForError ());
+ }
+ return true;
+ }
+
+ /// <summary>
+ /// Verifies whether the method in question is compatible with the delegate
+ /// Returns the method itself if okay and null if not.
+ /// </summary>
+ public static MethodBase VerifyMethod (EmitContext ec, Type delegate_type, MethodBase mb,
+ Location loc)
+ {
+ ParameterData pd = Invocation.GetParameterData (mb);
+
+ int pd_count = pd.Count;
+
+ Expression ml = Expression.MemberLookup (
+ ec, delegate_type, "Invoke", loc);
+
+ if (!(ml is MethodGroupExpr)) {
+ Report.Error (-100, loc, "Internal error: could not find Invoke method!");
+ return null;
+ }
+
+ MethodBase invoke_mb = ((MethodGroupExpr) ml).Methods [0];
+
+ ParameterData invoke_pd = Invocation.GetParameterData (invoke_mb);
+
+ if (invoke_pd.Count != pd_count)
+ return null;
+
+ for (int i = pd_count; i > 0; ) {
+ i--;
+
+ if (invoke_pd.ParameterType (i) == pd.ParameterType (i) &&
+ invoke_pd.ParameterModifier (i) == pd.ParameterModifier (i))
+ continue;
+ else {
+ return null;
+ }
+ }
+
+ if (((MethodInfo) invoke_mb).ReturnType == ((MethodInfo) mb).ReturnType)
+ return mb;
+ else
+ return null;
+ }
+
+ // <summary>
+ // Verifies whether the invocation arguments are compatible with the
+ // delegate's target method
+ // </summary>
+ public static bool VerifyApplicability (EmitContext ec,
+ Type delegate_type,
+ ArrayList args,
+ Location loc)
+ {
+ int arg_count;
+
+ if (args == null)
+ arg_count = 0;
+ else
+ arg_count = args.Count;
+
+ Expression ml = Expression.MemberLookup (
+ ec, delegate_type, "Invoke", loc);
+
+ if (!(ml is MethodGroupExpr)) {
+ Report.Error (-100, loc, "Internal error: could not find Invoke method!" + delegate_type);
+ return false;
+ }
+
+ MethodBase mb = ((MethodGroupExpr) ml).Methods [0];
+ ParameterData pd = Invocation.GetParameterData (mb);
+
+ int pd_count = pd.Count;
+
+ bool params_method = (pd_count != 0) &&
+ (pd.ParameterModifier (pd_count - 1) == Parameter.Modifier.PARAMS);
+
+ if (!params_method && pd_count != arg_count) {
+ Report.Error (1593, loc,
+ "Delegate '" + delegate_type.ToString ()
+ + "' does not take '" + arg_count + "' arguments");
+ return false;
+ }
+
+ //
+ // Consider the case:
+ // delegate void FOO(param object[] args);
+ // FOO f = new FOO(...);
+ // f(new object[] {1, 2, 3});
+ //
+ // This should be treated like f(1,2,3). This is done by ignoring the
+ // 'param' modifier for that invocation. If that fails, then the
+ // 'param' modifier is considered.
+ //
+ // One issue is that 'VerifyArgumentsCompat' modifies the elements of
+ // the 'args' array. However, the modifications appear idempotent.
+ // Normal 'Invocation's also have the same behaviour, implicitly.
+ //
+
+ bool ans = false;
+ if (arg_count == pd_count)
+ ans = Invocation.VerifyArgumentsCompat (ec, args, arg_count, mb, false, delegate_type, loc);
+ if (!ans && params_method)
+ ans = Invocation.VerifyArgumentsCompat (ec, args, arg_count, mb, true, delegate_type, loc);
+ return ans;
+ }
+
+ /// <summary>
+ /// Verifies whether the delegate in question is compatible with this one in
+ /// order to determine if instantiation from the same is possible.
+ /// </summary>
+ public static bool VerifyDelegate (EmitContext ec, Type delegate_type, Type probe_type, Location loc)
+ {
+ Expression ml = Expression.MemberLookup (
+ ec, delegate_type, "Invoke", loc);
+
+ if (!(ml is MethodGroupExpr)) {
+ Report.Error (-100, loc, "Internal error: could not find Invoke method!");
+ return false;
+ }
+
+ MethodBase mb = ((MethodGroupExpr) ml).Methods [0];
+ ParameterData pd = Invocation.GetParameterData (mb);
+
+ Expression probe_ml = Expression.MemberLookup (
+ ec, delegate_type, "Invoke", loc);
+
+ if (!(probe_ml is MethodGroupExpr)) {
+ Report.Error (-100, loc, "Internal error: could not find Invoke method!");
+ return false;
+ }
+
+ MethodBase probe_mb = ((MethodGroupExpr) probe_ml).Methods [0];
+ ParameterData probe_pd = Invocation.GetParameterData (probe_mb);
+
+ if (((MethodInfo) mb).ReturnType != ((MethodInfo) probe_mb).ReturnType)
+ return false;
+
+ if (pd.Count != probe_pd.Count)
+ return false;
+
+ for (int i = pd.Count; i > 0; ) {
+ i--;
+
+ if (pd.ParameterType (i) != probe_pd.ParameterType (i) ||
+ pd.ParameterModifier (i) != probe_pd.ParameterModifier (i))
+ return false;
+ }
+
+ return true;
+ }
+
+ public static string FullDelegateDesc (Type del_type, MethodBase mb, ParameterData pd)
+ {
+ StringBuilder sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));
+
+ sb.Append (" " + del_type.ToString ());
+ sb.Append (" (");
+
+ int length = pd.Count;
+
+ for (int i = length; i > 0; ) {
+ i--;
+
+ sb.Append (pd.ParameterDesc (length - i - 1));
+ if (i != 0)
+ sb.Append (", ");
+ }
+
+ sb.Append (")");
+ return sb.ToString ();
+
+ }
+
+ // Hack around System.Reflection as found everywhere else
+ public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
+ MemberFilter filter, object criteria)
+ {
+ ArrayList members = new ArrayList ();
+
+ if ((mt & MemberTypes.Method) != 0) {
+ if (ConstructorBuilder != null)
+ if (filter (ConstructorBuilder, criteria))
+ members.Add (ConstructorBuilder);
+
+ if (InvokeBuilder != null)
+ if (filter (InvokeBuilder, criteria))
+ members.Add (InvokeBuilder);
+
+ if (BeginInvokeBuilder != null)
+ if (filter (BeginInvokeBuilder, criteria))
+ members.Add (BeginInvokeBuilder);
+
+ if (EndInvokeBuilder != null)
+ if (filter (EndInvokeBuilder, criteria))
+ members.Add (EndInvokeBuilder);
+ }
+
+ return new MemberList (members);
+ }
+
+ public override MemberCache MemberCache {
+ get {
+ return null;
+ }
+ }
+
+ public Expression InstanceExpression {
+ get {
+ return instance_expr;
+ }
+ set {
+ instance_expr = value;
+ }
+ }
+
+ public MethodBase TargetMethod {
+ get {
+ return delegate_method;
+ }
+ set {
+ delegate_method = value;
+ }
+ }
+
+ public Type TargetReturnType {
+ get {
+ return ret_type;
+ }
+ }
+
+ public Type [] ParameterTypes {
+ get {
+ return param_types;
+ }
+ }
+
+ public override AttributeTargets AttributeTargets {
+ get {
+ return AttributeTargets.Delegate | AttributeTargets.ReturnValue;
+ }
+ }
+
+ protected override void VerifyObsoleteAttribute()
+ {
+ CheckUsageOfObsoleteAttribute (ret_type);
+
+ foreach (Type type in param_types) {
+ CheckUsageOfObsoleteAttribute (type);
+ }
+ }
+ }
+
+ //
+ // Base class for `NewDelegate' and `ImplicitDelegateCreation'
+ //
+ public abstract class DelegateCreation : Expression {
+ protected MethodBase constructor_method;
+ protected MethodBase delegate_method;
+ protected Expression delegate_instance_expr;
+
+ public DelegateCreation () {}
+
+ public static void Error_NoMatchingMethodForDelegate (EmitContext ec, MethodGroupExpr mg, Type type, Location loc)
+ {
+ string method_desc;
+
+ if (mg.Methods.Length > 1)
+ method_desc = mg.Methods [0].Name;
+ else
+ method_desc = Invocation.FullMethodDesc (mg.Methods [0]);
+
+ Expression invoke_method = Expression.MemberLookup (
+ ec, type, "Invoke", MemberTypes.Method,
+ Expression.AllBindingFlags, loc);
+ MethodBase method = ((MethodGroupExpr) invoke_method).Methods [0];
+ ParameterData param = Invocation.GetParameterData (method);
+ string delegate_desc = Delegate.FullDelegateDesc (type, method, param);
+
+ Report.Error (123, loc, "Method '" + method_desc + "' does not " +
+ "match delegate '" + delegate_desc + "'");
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ if (delegate_instance_expr == null ||
+ delegate_method.IsStatic)
+ ec.ig.Emit (OpCodes.Ldnull);
+ else
+ delegate_instance_expr.Emit (ec);
+
+ if (delegate_method.IsVirtual) {
+ ec.ig.Emit (OpCodes.Dup);
+ ec.ig.Emit (OpCodes.Ldvirtftn, (MethodInfo) delegate_method);
+ } else
+ ec.ig.Emit (OpCodes.Ldftn, (MethodInfo) delegate_method);
+ ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) constructor_method);
+ }
+
+ protected bool ResolveConstructorMethod (EmitContext ec)
+ {
+ Expression ml = Expression.MemberLookup (
+ ec, type, ".ctor", loc);
+
+ if (!(ml is MethodGroupExpr)) {
+ Report.Error (-100, loc, "Internal error: Could not find delegate constructor!");
+ return false;
+ }
+
+ constructor_method = ((MethodGroupExpr) ml).Methods [0];
+ return true;
+ }
+
+ protected Expression ResolveMethodGroupExpr (EmitContext ec, MethodGroupExpr mg)
+ {
+ foreach (MethodInfo mi in mg.Methods){
+ delegate_method = Delegate.VerifyMethod (ec, type, mi, loc);
+
+ if (delegate_method != null)
+ break;
+ }
+
+ if (delegate_method == null) {
+ Error_NoMatchingMethodForDelegate (ec, mg, type, loc);
+ return null;
+ }
+
+ //
+ // Check safe/unsafe of the delegate
+ //
+ if (!ec.InUnsafe){
+ ParameterData param = Invocation.GetParameterData (delegate_method);
+ int count = param.Count;
+
+ for (int i = 0; i < count; i++){
+ if (param.ParameterType (i).IsPointer){
+ Expression.UnsafeError (loc);
+ return null;
+ }
+ }
+ }
+
+ if (mg.InstanceExpression != null)
+ delegate_instance_expr = mg.InstanceExpression.Resolve (ec);
+ else {
+ if (ec.IsStatic){
+ if (!delegate_method.IsStatic){
+ Report.Error (120, loc,
+ "An object reference is required for the non-static method " +
+ delegate_method.Name);
+ return null;
+ }
+ delegate_instance_expr = null;
+ } else
+ delegate_instance_expr = ec.GetThis (loc);
+ }
+
+ if (delegate_instance_expr != null)
+ if (delegate_instance_expr.Type.IsValueType)
+ delegate_instance_expr = new BoxedCast (delegate_instance_expr);
+
+ eclass = ExprClass.Value;
+ return this;
+ }
+ }
+
+ //
+ // Created from the conversion code
+ //
+ public class ImplicitDelegateCreation : DelegateCreation {
+
+ ImplicitDelegateCreation (Type t, Location l)
+ {
+ type = t;
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ return this;
+ }
+
+ static public Expression Create (EmitContext ec, MethodGroupExpr mge, Type target_type, Location loc)
+ {
+ ImplicitDelegateCreation d = new ImplicitDelegateCreation (target_type, loc);
+ if (d.ResolveConstructorMethod (ec))
+ return d.ResolveMethodGroupExpr (ec, mge);
+ else
+ return null;
+ }
+ }
+
+ //
+ // A delegate-creation-expression, invoked from the `New' class
+ //
+ public class NewDelegate : DelegateCreation {
+ public ArrayList Arguments;
+
+ //
+ // This constructor is invoked from the `New' expression
+ //
+ public NewDelegate (Type type, ArrayList Arguments, Location loc)
+ {
+ this.type = type;
+ this.Arguments = Arguments;
+ this.loc = loc;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ if (Arguments == null || Arguments.Count != 1) {
+ Report.Error (149, loc,
+ "Method name expected");
+ return null;
+ }
+
+ if (!ResolveConstructorMethod (ec))
+ return null;
+
+ Argument a = (Argument) Arguments [0];
+
+ Expression invoke_method = Expression.MemberLookup (
+ ec, type, "Invoke", MemberTypes.Method,
+ Expression.AllBindingFlags, loc);
+
+ if (invoke_method == null) {
+ Report.Error (-200, loc, "Internal error ! Could not find Invoke method!");
+ return null;
+ }
+
+ if (!a.ResolveMethodGroup (ec, loc))
+ return null;
+
+ Expression e = a.Expr;
+
+ MethodGroupExpr mg = e as MethodGroupExpr;
+ if (mg != null)
+ return ResolveMethodGroupExpr (ec, mg);
+
+ Type e_type = e.Type;
+
+ if (!TypeManager.IsDelegateType (e_type)) {
+ e.Error_UnexpectedKind ("method");
+ return null;
+ }
+
+ // This is what MS' compiler reports. We could always choose
+ // to be more verbose and actually give delegate-level specifics
+
+ if (!Delegate.VerifyDelegate (ec, type, e_type, loc)) {
+ Report.Error (29, loc, "Cannot implicitly convert type '" + e_type + "' " +
+ "to type '" + type + "'");
+ return null;
+ }
+
+ delegate_instance_expr = e;
+ delegate_method = ((MethodGroupExpr) invoke_method).Methods [0];
+
+ eclass = ExprClass.Value;
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ if (delegate_instance_expr == null || delegate_method.IsStatic)
+ ec.ig.Emit (OpCodes.Ldnull);
+ else
+ delegate_instance_expr.Emit (ec);
+
+ if (delegate_method.IsVirtual) {
+ ec.ig.Emit (OpCodes.Dup);
+ ec.ig.Emit (OpCodes.Ldvirtftn, (MethodInfo) delegate_method);
+ } else
+ ec.ig.Emit (OpCodes.Ldftn, (MethodInfo) delegate_method);
+ ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) constructor_method);
+ }
+ }
+
+ public class DelegateInvocation : ExpressionStatement {
+
+ public Expression InstanceExpr;
+ public ArrayList Arguments;
+
+ MethodBase method;
+
+ public DelegateInvocation (Expression instance_expr, ArrayList args, Location loc)
+ {
+ this.InstanceExpr = instance_expr;
+ this.Arguments = args;
+ this.loc = loc;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ if (InstanceExpr is EventExpr) {
+
+ EventInfo ei = ((EventExpr) InstanceExpr).EventInfo;
+
+ Expression ml = MemberLookup (
+ ec, ec.ContainerType, ei.Name,
+ MemberTypes.Event, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
+
+ if (ml == null) {
+ //
+ // If this is the case, then the Event does not belong
+ // to this Type and so, according to the spec
+ // cannot be accessed directly
+ //
+ // Note that target will not appear as an EventExpr
+ // in the case it is being referenced within the same type container;
+ // it will appear as a FieldExpr in that case.
+ //
+
+ Assign.error70 (ei, loc);
+ return null;
+ }
+ }
+
+
+ Type del_type = InstanceExpr.Type;
+ if (del_type == null)
+ return null;
+
+ if (Arguments != null){
+ foreach (Argument a in Arguments){
+ if (!a.Resolve (ec, loc))
+ return null;
+ }
+ }
+
+ if (!Delegate.VerifyApplicability (ec, del_type, Arguments, loc))
+ return null;
+
+ Expression lookup = Expression.MemberLookup (ec, del_type, "Invoke", loc);
+ if (!(lookup is MethodGroupExpr)) {
+ Report.Error (-100, loc, "Internal error: could not find Invoke method!");
+ return null;
+ }
+
+ method = ((MethodGroupExpr) lookup).Methods [0];
+ type = ((MethodInfo) method).ReturnType;
+ eclass = ExprClass.Value;
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ //
+ // Invocation on delegates call the virtual Invoke member
+ // so we are always `instance' calls
+ //
+ Invocation.EmitCall (ec, false, false, InstanceExpr, method, Arguments, loc);
+ }
+
+ public override void EmitStatement (EmitContext ec)
+ {
+ Emit (ec);
+ //
+ // Pop the return value if there is one
+ //
+ if (method is MethodInfo){
+ if (((MethodInfo) method).ReturnType != TypeManager.void_type)
+ ec.ig.Emit (OpCodes.Pop);
+ }
+ }
+
+ }
+}