[mcs] Add more of undocumented C#6 improved overload resolution
authorMarek Safar <marek.safar@gmail.com>
Tue, 31 May 2016 16:37:01 +0000 (18:37 +0200)
committerMarek Safar <marek.safar@gmail.com>
Tue, 31 May 2016 16:40:50 +0000 (18:40 +0200)
mcs/mcs/ecore.cs
mcs/tests/test-935.cs [new file with mode: 0644]
mcs/tests/ver-il-net_4_x.xml

index 63d6367309d7150bc430e8da642c61072b66a955..127df271c794c073834a48f79eb922e6c569c6da 100644 (file)
@@ -4482,8 +4482,8 @@ namespace Mono.CSharp {
                                        //
                                        // Uwrap delegate from Expression<T>
                                        //
-                                       q = TypeManager.GetTypeArguments (q)[0];
-                                       p = TypeManager.GetTypeArguments (p)[0];
+                                       q = TypeManager.GetTypeArguments (q) [0];
+                                       p = TypeManager.GetTypeArguments (p) [0];
                                }
 
                                var p_m = Delegate.GetInvokeMethod (p);
@@ -4510,10 +4510,10 @@ namespace Mono.CSharp {
                                // if p has a return type Y, and q is void returning, then C1 is the better conversion.
                                //
                                if (q.Kind == MemberKind.Void) {
-                                       return p.Kind != MemberKind.Void ? 1: 0;
+                                       return p.Kind != MemberKind.Void ? 1 : 0;
                                }
 
-                               var am = (AnonymousMethodExpression) a.Expr;
+                               var am = (AnonymousMethodExpression)a.Expr;
 
                                //
                                // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
@@ -4521,8 +4521,8 @@ namespace Mono.CSharp {
                                //
                                if (p.IsGenericTask || q.IsGenericTask) {
                                        if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
-                                               q = q.TypeArguments[0];
-                                               p = p.TypeArguments[0];
+                                               q = q.TypeArguments [0];
+                                               p = p.TypeArguments [0];
                                        }
                                }
 
@@ -4548,11 +4548,63 @@ namespace Mono.CSharp {
                        if (argument_type == q)
                                return 2;
 
-                       //
-                       // The parameters are identicial and return type is not void, use better type conversion
-                       // on return type to determine better one
-                       //
-                       return BetterTypeConversion (ec, p, q);
+                       return IsBetterConversionTarget (ec, p, q);
+               }
+
+               static int IsBetterConversionTarget (ResolveContext rc, TypeSpec p, TypeSpec q)
+               {
+                       if ((p.Kind == MemberKind.Delegate || p.IsExpressionTreeType) && (q.Kind == MemberKind.Delegate || q.IsExpressionTreeType)) {
+
+                               if (p.Kind != MemberKind.Delegate) {
+                                       p = TypeManager.GetTypeArguments (p) [0];
+                               }
+
+                               if (q.Kind != MemberKind.Delegate) {
+                                       q = TypeManager.GetTypeArguments (q) [0];
+                               }
+
+                               var p_m = Delegate.GetInvokeMethod (p);
+                               var q_m = Delegate.GetInvokeMethod (q);
+
+                               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.Kind == MemberKind.Void) {
+                                       return q.Kind != MemberKind.Void ? 2 : 0;
+                               }
+
+                               //
+                               // if p has a return type Y, and q is void returning, then C1 is the better conversion.
+                               //
+                               if (q.Kind == MemberKind.Void) {
+                                       return p.Kind != MemberKind.Void ? 1 : 0;
+                               }
+
+                               return IsBetterConversionTarget (rc, p, q);
+                       }
+
+                       if (p.IsGenericTask && q.IsGenericTask) {
+                               q = q.TypeArguments [0];
+                               p = p.TypeArguments [0];
+                               return IsBetterConversionTarget (rc, p, q);
+                       }
+
+                       if (p.IsNullableType) {
+                               p = Nullable.NullableInfo.GetUnderlyingType (p);
+                               if (!BuiltinTypeSpec.IsPrimitiveType (p))
+                                       return 0;
+                       }
+
+                       if (q.IsNullableType) {
+                               q = Nullable.NullableInfo.GetUnderlyingType (q);
+                               if (!BuiltinTypeSpec.IsPrimitiveType (q))
+                                       return 0;
+                       }
+
+                       return BetterTypeConversion (rc, p, q);
                }
 
                //
@@ -4625,8 +4677,6 @@ namespace Mono.CSharp {
                                return 1;
                        }
 
-                       // FIXME: handle lifted operators
-
                        // TODO: this is expensive
                        Expression p_tmp = new EmptyExpression (p);
                        Expression q_tmp = new EmptyExpression (q);
diff --git a/mcs/tests/test-935.cs b/mcs/tests/test-935.cs
new file mode 100644 (file)
index 0000000..c47d89d
--- /dev/null
@@ -0,0 +1,74 @@
+using System;
+using System.Threading.Tasks;
+using System.Linq.Expressions;
+
+public static class Program
+{
+       public delegate void DelegateVoid (int arg);
+       public delegate int DelegateInt (string arg);
+
+       public static int Main () 
+       { 
+               Foo (Bar);
+
+               TT (null);
+               NN (0);
+               NN2 (1);
+               Complex (null);
+               return 0;
+       }
+
+       static void TT (Task<string> a)
+       {
+       }
+
+       static void TT (Task<object> b)
+       {
+               throw new ApplicationException ("wrong overload");
+       }
+
+       static void NN (sbyte a)
+       {
+       }
+
+       static void NN (uint? b)
+       {
+               throw new ApplicationException ("wrong overload");
+       }
+
+       static void NN2 (sbyte? a)
+       {
+       }
+
+       static void NN2 (uint? b)
+       {
+               throw new ApplicationException ("wrong overload");
+       }
+
+       public static void Bar (int arg) 
+       {
+       }
+
+       public static int Bar (string arg)
+       { 
+               return  2;
+       }
+
+       public static void Foo (DelegateVoid input)
+       {
+               throw new ApplicationException ("wrong overload");
+       }
+
+       public static void Foo (DelegateInt input)
+       {
+       }
+
+       static void Complex (Expression<Func<Task<short>>> arg)
+       {
+       }
+
+       static void Complex (Expression<Func<Task<ulong>>> arg)
+       {
+               throw new ApplicationException ("wrong overload");
+       }
+}
\ No newline at end of file
index 7ba3329b35d0b6ec07745f7a19c895346b2b589b..f49ba8fbf1197df783b10d1dc6e8885bc8c428f7 100644 (file)
       </method>
     </type>
   </test>
+  <test name="test-935.cs">
+    <type name="Program">
+      <method name="Int32 Main()" attrs="150">
+        <size>73</size>
+      </method>
+      <method name="Void TT(System.Threading.Tasks.Task`1[System.String])" attrs="145">
+        <size>2</size>
+      </method>
+      <method name="Void TT(System.Threading.Tasks.Task`1[System.Object])" attrs="145">
+        <size>12</size>
+      </method>
+      <method name="Void NN(SByte)" attrs="145">
+        <size>2</size>
+      </method>
+      <method name="Void NN(System.Nullable`1[System.UInt32])" attrs="145">
+        <size>12</size>
+      </method>
+      <method name="Void NN2(System.Nullable`1[System.SByte])" attrs="145">
+        <size>2</size>
+      </method>
+      <method name="Void NN2(System.Nullable`1[System.UInt32])" attrs="145">
+        <size>12</size>
+      </method>
+      <method name="Void Bar(Int32)" attrs="150">
+        <size>2</size>
+      </method>
+      <method name="Int32 Bar(System.String)" attrs="150">
+        <size>10</size>
+      </method>
+      <method name="Void Foo(DelegateVoid)" attrs="150">
+        <size>12</size>
+      </method>
+      <method name="Void Foo(DelegateInt)" attrs="150">
+        <size>2</size>
+      </method>
+      <method name="Void Complex(System.Linq.Expressions.Expression`1[System.Func`1[System.Threading.Tasks.Task`1[System.Int16]]])" attrs="145">
+        <size>2</size>
+      </method>
+      <method name="Void Complex(System.Linq.Expressions.Expression`1[System.Func`1[System.Threading.Tasks.Task`1[System.UInt64]]])" attrs="145">
+        <size>12</size>
+      </method>
+    </type>
+    <type name="Program+DelegateVoid">
+      <method name="Void Invoke(Int32)" attrs="454">
+        <size>0</size>
+      </method>
+      <method name="System.IAsyncResult BeginInvoke(Int32, System.AsyncCallback, System.Object)" attrs="454">
+        <size>0</size>
+      </method>
+      <method name="Void EndInvoke(System.IAsyncResult)" attrs="454">
+        <size>0</size>
+      </method>
+      <method name="Void .ctor(Object, IntPtr)" attrs="6278">
+        <size>0</size>
+      </method>
+    </type>
+    <type name="Program+DelegateInt">
+      <method name="Int32 Invoke(System.String)" attrs="454">
+        <size>0</size>
+      </method>
+      <method name="System.IAsyncResult BeginInvoke(System.String, System.AsyncCallback, System.Object)" attrs="454">
+        <size>0</size>
+      </method>
+      <method name="Int32 EndInvoke(System.IAsyncResult)" attrs="454">
+        <size>0</size>
+      </method>
+      <method name="Void .ctor(Object, IntPtr)" attrs="6278">
+        <size>0</size>
+      </method>
+    </type>
+  </test>
   <test name="test-94.cs">
     <type name="Base">
       <method name="Int32 IVehicle.Start()" attrs="481">