Better anonymous methods require same parameter types
authorMarek Safar <marek.safar@gmail.com>
Fri, 7 Jan 2011 09:55:44 +0000 (09:55 +0000)
committerMarek Safar <marek.safar@gmail.com>
Fri, 7 Jan 2011 09:58:14 +0000 (09:58 +0000)
mcs/errors/cs0121-19.cs [new file with mode: 0644]
mcs/mcs/ecore.cs

diff --git a/mcs/errors/cs0121-19.cs b/mcs/errors/cs0121-19.cs
new file mode 100644 (file)
index 0000000..38ccfe9
--- /dev/null
@@ -0,0 +1,20 @@
+// CS0121: The call is ambiguous between the following methods or properties: `C.M(System.Func<byte,int>)' and `C.M(System.Action<int>)'
+// Line: 18
+
+using System;
+
+class C
+{
+       static void M (Func<byte,int> arg)
+       {
+       }
+       
+       static void M (Action<int> arg)
+       {
+       }
+
+       static void Main()
+       {
+               M(l => l.GetHashCode());
+       }
+}
index 03feffc60e16bfae25cac9de4b437336b65d07e6..acd296884e46fcf7da02ad2bf3ced0b274ab05f7 100644 (file)
@@ -3420,23 +3420,51 @@ namespace Mono.CSharp {
                static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
                {
                        TypeSpec argument_type = a.Type;
+
+                       //
+                       // If argument is an anonymous function
+                       //
                        if (argument_type == InternalType.AnonymousMethod && RootContext.Version > LanguageVersion.ISO_2) {
                                //
-                               // Uwrap delegate from Expression<T>
+                               // p and q are delegate types or expression tree types
                                //
-                               if (p.GetDefinition () == TypeManager.expression_type) {
+                               if (p.GetDefinition () == TypeManager.expression_type || q.GetDefinition () == TypeManager.expression_type) {
+                                       if (q.MemberDefinition != p.MemberDefinition) {
+                                               return 0;
+                                       }
+
+                                       //
+                                       // Uwrap delegate from Expression<T>
+                                       //
+                                       q = TypeManager.GetTypeArguments (q)[0];
                                        p = TypeManager.GetTypeArguments (p)[0];
                                }
-                               if (q.GetDefinition () == TypeManager.expression_type) {
-                                       q = TypeManager.GetTypeArguments (q)[0];
+
+                               var p_m = Delegate.GetInvokeMethod (ec.Compiler, p);
+                               var q_m = Delegate.GetInvokeMethod (ec.Compiler, q);
+
+                               //
+                               // With identical parameter lists
+                               //
+                               if (!TypeSpecComparer.Equals (p_m.Parameters.Types,q_m.Parameters.Types))
+                                       return 0;
+
+                               p = p_m.ReturnType;
+                               q = q_m.ReturnType;
+
+                               //
+                               // if p is void returning, and q has a return type Y, then C2 is the better conversion.
+                               //
+                               if (p == TypeManager.void_type) {
+                                       return q != TypeManager.void_type ? 2 : 0;
                                }
 
-                               p = Delegate.GetInvokeMethod (ec.Compiler, p).ReturnType;
-                               q = Delegate.GetInvokeMethod (ec.Compiler, q).ReturnType;
-                               if (p == TypeManager.void_type && q != TypeManager.void_type)
-                                       return 2;
-                               if (q == TypeManager.void_type && p != TypeManager.void_type)
-                                       return 1;
+                               //
+                               // if p has a return type Y, and q is void returning, then C1 is the better conversion.
+                               //
+                               if (q == TypeManager.void_type) {
+                                       return p != TypeManager.void_type ? 1: 0;
+                               }
                        } else {
                                if (argument_type == p)
                                        return 1;