Implement Method Group Conversions (34.8) from the Anonymous Methods spec.
authorMiguel de Icaza <miguel@gnome.org>
Fri, 16 Jan 2004 23:03:30 +0000 (23:03 -0000)
committerMiguel de Icaza <miguel@gnome.org>
Fri, 16 Jan 2004 23:03:30 +0000 (23:03 -0000)
2004-01-16  Miguel de Icaza  <miguel@ximian.com>

* expression.cs (Binary.ResolveOperator): Perform an implicit
conversion from MethodGroups to their delegate types on the
Addition operation.

* delegate.cs: Introduce a new class DelegateCreation that is the
base class for `NewDelegate' and `ImplicitDelegateCreation',
factor some code in here.

* convert.cs (Convert.ImplicitConversionStandard): Add an implicit
conversion from MethodGroups to compatible delegate types.

* ecore.cs (Expression.Resolve): Do not flag error 654
(Methodgroupd needs parenthesis) if running on the V2 compiler, as
we allow conversions from MethodGroups to delegate types now.

* assign.cs (Assign.DoResolve): Do not flag errors on methodgroup
assignments in v2 either.

svn path=/trunk/mcs/; revision=22197

mcs/mcs/ChangeLog
mcs/mcs/assign.cs
mcs/mcs/convert.cs
mcs/mcs/delegate.cs
mcs/mcs/ecore.cs
mcs/mcs/expression.cs

index f818ad589da896375669dcf424cdb04fbd6c247b..ab8d00f1780f98efc4e33dfae99febd0be0f3768 100755 (executable)
@@ -1,3 +1,23 @@
+2004-01-16  Miguel de Icaza  <miguel@ximian.com>
+
+       * expression.cs (Binary.ResolveOperator): Perform an implicit
+       conversion from MethodGroups to their delegate types on the
+       Addition operation.
+
+       * delegate.cs: Introduce a new class DelegateCreation that is the
+       base class for `NewDelegate' and `ImplicitDelegateCreation',
+       factor some code in here.
+
+       * convert.cs (Convert.ImplicitConversionStandard): Add an implicit
+       conversion from MethodGroups to compatible delegate types. 
+
+       * ecore.cs (Expression.Resolve): Do not flag error 654
+       (Methodgroupd needs parenthesis) if running on the V2 compiler, as
+       we allow conversions from MethodGroups to delegate types now.
+       
+       * assign.cs (Assign.DoResolve): Do not flag errors on methodgroup
+       assignments in v2 either.
+
 2004-01-10  Miguel de Icaza  <miguel@ximian.com>
 
        * ecore.cs (FieldExpr.AddressOf): Fix generated IL for accessing
index dae00366584056cbf497f1f09ac838a78a6414b8..ec21026574f4b946fd4f3bce41a3f049dc2f945b 100755 (executable)
@@ -262,11 +262,12 @@ namespace Mono.CSharp {
                        if ((source.eclass == ExprClass.Type) && (source is TypeExpr)) {
                                source.Error_UnexpectedKind ("variable or value");
                                return null;
-                       } else if (source is MethodGroupExpr){
+                       } else if (!RootContext.V2 && (source is MethodGroupExpr)){
                                ((MethodGroupExpr) source).ReportUsageError ();
                                return null;
-                       }
 
+                       }
+                       
                        if (target_type == source_type)
                                return this;
                        
index d6ac8f890d72e371051c733a452e1d25090fa157..2fb9ce01ffa53cff168cc32f54abed223eec13ec 100644 (file)
@@ -991,7 +991,7 @@ namespace Mono.CSharp {
                ///   in a context that expects a `target_type'. 
                /// </summary>
                static public Expression ImplicitConversion (EmitContext ec, Expression expr,
-                                                         Type target_type, Location loc)
+                                                            Type target_type, Location loc)
                {
                        Expression e;
 
@@ -1026,6 +1026,18 @@ namespace Mono.CSharp {
                        Type expr_type = expr.Type;
                        Expression e;
 
+                       if (expr.eclass == ExprClass.MethodGroup){
+                               if (!TypeManager.IsDelegateType (target_type)){
+                                       Report.Error (428, loc,
+                                                     String.Format (
+                                                          "Cannot convert method group to `{0}', since it is not a delegate",
+                                                          TypeManager.CSharpName (target_type)));
+                                       return null;
+                               }
+
+                               return ImplicitDelegateCreation.Create (ec, (MethodGroupExpr) expr, target_type, loc);
+                       }
+                       
                        if (expr_type == target_type && !(expr is NullLiteral))
                                return expr;
 
index 8a3328c412cdf1772ed7dc9a069e6b34b1672a51..93aa6f6e1be03b2829180f14b8215d5e6ba7149b 100644 (file)
@@ -573,16 +573,149 @@ namespace Mono.CSharp {
        }\r
 \r
        //\r
-       // A delegate-creation-expression\r
+       // Base class for `NewDelegate' and `ImplicitDelegateCreation'\r
        //\r
-       public class NewDelegate : Expression {\r
+       public abstract class DelegateCreation : Expression {\r
+               protected MethodBase constructor_method;\r
+               protected MethodBase delegate_method;\r
+               protected Expression delegate_instance_expr;\r
 \r
-               public ArrayList Arguments;\r
+               public DelegateCreation () {}\r
 \r
-               MethodBase constructor_method;\r
-               MethodBase delegate_method;\r
-               Expression delegate_instance_expr;\r
+               public static void Error_NoMatchingMethodForDelegate (MethodGroupExpr mg, Type t, MethodBase method, Location loc)\r
+               {\r
+                       string method_desc;\r
+                       \r
+                       if (mg.Methods.Length > 1)\r
+                               method_desc = mg.Methods [0].Name;\r
+                       else\r
+                               method_desc = Invocation.FullMethodDesc (mg.Methods [0]);\r
+\r
+                       ParameterData param = Invocation.GetParameterData (method);\r
+                       string delegate_desc = Delegate.FullDelegateDesc (t, method, param);\r
+                       \r
+                       Report.Error (123, loc, "Method '" + method_desc + "' does not " +\r
+                                     "match delegate '" + delegate_desc + "'");\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
+                       if (delegate_method.IsVirtual) {\r
+                               ec.ig.Emit (OpCodes.Dup);\r
+                               ec.ig.Emit (OpCodes.Ldvirtftn, (MethodInfo) delegate_method);\r
+                       } else\r
+                               ec.ig.Emit (OpCodes.Ldftn, (MethodInfo) delegate_method);\r
+                       ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) constructor_method);\r
+               }\r
+\r
+               protected bool ResolveConstructorMethod (EmitContext ec)\r
+               {\r
+                       Expression ml = Expression.MemberLookup (\r
+                               ec, type, ".ctor", loc);\r
+\r
+                       if (!(ml is MethodGroupExpr)) {\r
+                               Report.Error (-100, loc, "Internal error: Could not find delegate constructor!");\r
+                               return false;\r
+                       }\r
+\r
+                       constructor_method = ((MethodGroupExpr) ml).Methods [0];\r
+                       return true;\r
+               }\r
+\r
+               protected Expression ResolveMethodGroupExpr (EmitContext ec, MethodGroupExpr mg)\r
+               {\r
+                       foreach (MethodInfo mi in mg.Methods){\r
+                               delegate_method  = Delegate.VerifyMethod (ec, type, mi, loc);\r
+                               \r
+                               if (delegate_method != null)\r
+                                       break;\r
+                       }\r
+                       \r
+                       if (delegate_method == null) {\r
+                               Error_NoMatchingMethodForDelegate (mg, type, delegate_method, loc);\r
+                               return null;\r
+                       }\r
+                       \r
+                       //\r
+                       // Check safe/unsafe of the delegate\r
+                       //\r
+                       if (!ec.InUnsafe){\r
+                               ParameterData param = Invocation.GetParameterData (delegate_method);\r
+                               int count = param.Count;\r
+                               \r
+                               for (int i = 0; i < count; i++){\r
+                                       if (param.ParameterType (i).IsPointer){\r
+                                               Expression.UnsafeError (loc);\r
+                                               return null;\r
+                                       }\r
+                               }\r
+                       }\r
+                       \r
+                       if (mg.InstanceExpression != null)\r
+                               delegate_instance_expr = mg.InstanceExpression.Resolve (ec);\r
+                       else {\r
+                               if (ec.IsStatic){\r
+                                       if (!delegate_method.IsStatic){\r
+                                               Report.Error (120, loc,\r
+                                                             "An object reference is required for the non-static method " +\r
+                                                             delegate_method.Name);\r
+                                               return null;\r
+                                       }\r
+                                       delegate_instance_expr = null;\r
+                               } else\r
+                                       delegate_instance_expr = ec.GetThis (loc);\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
 \r
+       //\r
+       // Created from the conversion code\r
+       //\r
+       public class ImplicitDelegateCreation : DelegateCreation {\r
+\r
+               ImplicitDelegateCreation (Type t, Location l)\r
+               {\r
+                       type = t;\r
+                       loc = l;\r
+               }\r
+\r
+               public override Expression DoResolve (EmitContext ec)\r
+               {\r
+                       return this;\r
+               }\r
+               \r
+               static public Expression Create (EmitContext ec, MethodGroupExpr mge, Type target_type, Location loc)\r
+               {\r
+                       ImplicitDelegateCreation d = new ImplicitDelegateCreation (target_type, loc);\r
+                       if (d.ResolveConstructorMethod (ec))\r
+                               return d.ResolveMethodGroupExpr (ec, mge);\r
+                       else\r
+                               return null;\r
+               }\r
+       }\r
+       \r
+       //\r
+       // A delegate-creation-expression, invoked from the `New' class \r
+       //\r
+       public class NewDelegate : DelegateCreation {\r
+               public ArrayList Arguments;\r
+\r
+               //\r
+               // This constructor is invoked from the `New' expression\r
+               //\r
                public NewDelegate (Type type, ArrayList Arguments, Location loc)\r
                {\r
                        this.type = type;\r
@@ -598,22 +731,11 @@ namespace Mono.CSharp {
                                return null;\r
                        }\r
 \r
-                       Expression ml = Expression.MemberLookup (\r
-                               ec, type, ".ctor", loc);\r
-\r
-                       if (!(ml is MethodGroupExpr)) {\r
-                               Report.Error (-100, loc, "Internal error: Could not find delegate constructor!");\r
+                       if (!ResolveConstructorMethod (ec))\r
                                return null;\r
-                       }\r
 \r
-                       constructor_method = ((MethodGroupExpr) ml).Methods [0];\r
                        Argument a = (Argument) Arguments [0];\r
                        \r
-                       if (!a.ResolveMethodGroup (ec, Location))\r
-                               return null;\r
-                       \r
-                       Expression e = a.Expr;\r
-\r
                        Expression invoke_method = Expression.MemberLookup (\r
                                ec, type, "Invoke", MemberTypes.Method,\r
                                Expression.AllBindingFlags, loc);\r
@@ -623,70 +745,14 @@ namespace Mono.CSharp {
                                return null;\r
                        }\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, loc);\r
-\r
-                                       if (delegate_method != null)\r
-                                               break;\r
-                               }\r
-                                       \r
-                               if (delegate_method == null) {\r
-                                       string method_desc;\r
-                                       if (mg.Methods.Length > 1)\r
-                                               method_desc = mg.Methods [0].Name;\r
-                                       else\r
-                                               method_desc = Invocation.FullMethodDesc (mg.Methods [0]);\r
-\r
-                                       MethodBase dm = ((MethodGroupExpr) invoke_method).Methods [0];\r
-                                       ParameterData param = Invocation.GetParameterData (dm);\r
-                                       string delegate_desc = Delegate.FullDelegateDesc (type, dm, param);\r
-\r
-                                       Report.Error (123, loc, "Method '" + method_desc + "' does not " +\r
-                                                     "match delegate '" + delegate_desc + "'");\r
-\r
-                                       return null;\r
-                               }\r
-\r
-                               //\r
-                               // Check safe/unsafe of the delegate\r
-                               //\r
-                               if (!ec.InUnsafe){\r
-                                       ParameterData param = Invocation.GetParameterData (delegate_method);\r
-                                       int count = param.Count;\r
-                                       \r
-                                       for (int i = 0; i < count; i++){\r
-                                               if (param.ParameterType (i).IsPointer){\r
-                                                       Expression.UnsafeError (loc);\r
-                                                       return null;\r
-                                               }\r
-                                       }\r
-                               }\r
-                                               \r
-                               if (mg.InstanceExpression != null)\r
-                                       delegate_instance_expr = mg.InstanceExpression.Resolve (ec);\r
-                               else {\r
-                                       if (ec.IsStatic){\r
-                                               if (!delegate_method.IsStatic){\r
-                                                       Report.Error (120, loc,\r
-                                                                     "An object reference is required for the non-static method " +\r
-                                                                     delegate_method.Name);\r
-                                                       return null;\r
-                                               }\r
-                                               delegate_instance_expr = null;\r
-                                       } else\r
-                                               delegate_instance_expr = ec.GetThis (loc);\r
-                               }\r
+                       if (!a.ResolveMethodGroup (ec, loc))\r
+                               return null;\r
+                       \r
+                       Expression e = a.Expr;\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
+                       MethodGroupExpr mg = e as MethodGroupExpr;\r
+                       if (mg != null)\r
+                               return ResolveMethodGroupExpr (ec, mg);\r
 \r
                        Type e_type = e.Type;\r
 \r
@@ -713,8 +779,7 @@ namespace Mono.CSharp {
                \r
                public override void Emit (EmitContext ec)\r
                {\r
-                       if (delegate_instance_expr == null ||\r
-                           delegate_method.IsStatic)\r
+                       if (delegate_instance_expr == null || delegate_method.IsStatic)\r
                                ec.ig.Emit (OpCodes.Ldnull);\r
                        else\r
                                delegate_instance_expr.Emit (ec);\r
index 9adc326b06b4596112192b55b71b5eaa215389d0..9f2b5218f2cc92fe7395a4237848187f01c40043 100755 (executable)
@@ -314,9 +314,11 @@ namespace Mono.CSharp {
                                break;
 
                        case ExprClass.MethodGroup:
-                               if ((flags & ResolveFlags.MethodGroup) == 0) {
-                                       ((MethodGroupExpr) e).ReportUsageError ();
-                                       return null;
+                               if (!RootContext.V2){
+                                       if ((flags & ResolveFlags.MethodGroup) == 0) {
+                                               ((MethodGroupExpr) e).ReportUsageError ();
+                                               return null;
+                                       }
                                }
                                break;
 
index e1edcf2e22959bf2db70550087ea535865f92a75..6e5cca07c422b3050dfc82c57c28fa30d9baac5f 100755 (executable)
@@ -2310,10 +2310,6 @@ namespace Mono.CSharp {
                                }
                        }
                        
-                       //
-                       // Step 2: Default operations on CLI native types.
-                       //
-
                        //
                        // Step 0: String concatenation (because overloading will get this wrong)
                        //
@@ -2490,28 +2486,37 @@ namespace Mono.CSharp {
                        // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
                        //
                        if (oper == Operator.Addition || oper == Operator.Subtraction) {
-                               if (l.IsSubclassOf (TypeManager.delegate_type) &&
-                                   r.IsSubclassOf (TypeManager.delegate_type)) {
-                                       MethodInfo method;
-                                       ArrayList args = new ArrayList (2);
-                                       
-                                       args = new ArrayList (2);
-                                       args.Add (new Argument (left, Argument.AType.Expression));
-                                       args.Add (new Argument (right, Argument.AType.Expression));
-                                       
-                                       if (oper == Operator.Addition)
-                                               method = TypeManager.delegate_combine_delegate_delegate;
-                                       else
-                                               method = TypeManager.delegate_remove_delegate_delegate;
-
-                                       if (l != r) {
-                                               Error_OperatorCannotBeApplied ();
-                                               return null;
+                               if (l.IsSubclassOf (TypeManager.delegate_type)){
+                                       if (right.eclass == ExprClass.MethodGroup && RootContext.V2){
+                                               Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
+                                               if (tmp == null)
+                                                       return null;
+                                               right = tmp;
+                                               r = right.Type;
+                                       }
+                               
+                                       if (r.IsSubclassOf (TypeManager.delegate_type)){
+                                               MethodInfo method;
+                                               ArrayList args = new ArrayList (2);
+                                               
+                                               args = new ArrayList (2);
+                                               args.Add (new Argument (left, Argument.AType.Expression));
+                                               args.Add (new Argument (right, Argument.AType.Expression));
+                                               
+                                               if (oper == Operator.Addition)
+                                                       method = TypeManager.delegate_combine_delegate_delegate;
+                                               else
+                                                       method = TypeManager.delegate_remove_delegate_delegate;
+                                               
+                                               if (l != r) {
+                                                       Error_OperatorCannotBeApplied ();
+                                                       return null;
+                                               }
+                                               
+                                               return new BinaryDelegate (l, method, args);
                                        }
-
-                                       return new BinaryDelegate (l, method, args);
                                }
-
+                               
                                //
                                // Pointer arithmetic:
                                //