Skip to content

Commit

Permalink
Fixes overload resolution regression with ValueTuple (#20587)
Browse files Browse the repository at this point in the history
Fixes #20494
Adds a test for #20583
  • Loading branch information
gafter committed Jul 9, 2017
1 parent f8b1d56 commit 3565c81
Show file tree
Hide file tree
Showing 4 changed files with 275 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1782,8 +1782,8 @@ private static BetterResult MoreSpecificType(TypeSymbol t1, TypeSymbol t2, ref H
// argument is more specific and no type argument is less specific than the
// corresponding type argument in the other.

var n1 = t1 as NamedTypeSymbol;
var n2 = t2 as NamedTypeSymbol;
var n1 = t1.TupleUnderlyingTypeOrSelf() as NamedTypeSymbol;
var n2 = t2.TupleUnderlyingTypeOrSelf() as NamedTypeSymbol;
Debug.Assert(((object)n1 == null) == ((object)n2 == null));

if ((object)n1 == null)
Expand Down
143 changes: 143 additions & 0 deletions src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23412,5 +23412,148 @@ void M()
Assert.Equal("(System.Int32, System.String, System.Int32)", model.GetTypeInfo(tuple).ConvertedType.ToTestDisplayString());
Assert.Equal(ConversionKind.NoConversion, model.GetConversion(tuple).Kind);
}

[Fact]
[WorkItem(20494, "https://github.com/dotnet/roslyn/issues/20494")]
public void MoreGenericTieBreaker_01()
{
var source =
@"using System;
public class C
{
public static void Main()
{
A<A<int>> a = null;
M1(a); // ok, selects M1<T>(A<A<T>> a)

var b = default(ValueTuple<ValueTuple<int, int>, int>);
M2(b); // ok, should select M2<T>(ValueTuple<ValueTuple<T, int>, int> a)
}
public static void M1<T>(A<T> a) { Console.Write(1); }
public static void M1<T>(A<A<T>> a) { Console.Write(2); }

public static void M2<T>(ValueTuple<T, int> a) { Console.Write(3); }
public static void M2<T>(ValueTuple<ValueTuple<T, int>, int> a) { Console.Write(4); }
}

public class A<T> {}";
var comp = CompileAndVerify(source, additionalRefs: s_valueTupleRefs, expectedOutput: "24");
}

[Fact]
[WorkItem(20494, "https://github.com/dotnet/roslyn/issues/20494")]
public void MoreGenericTieBreaker_01b()
{
var source =
@"using System;
public class C
{
public static void Main()
{
var b = ((0, 0), 0);
M2(b); // ok, should select M2<T>(((T, int), int) a)
}
public static void M2<T>((T, int) a) { Console.Write(3); }
public static void M2<T>(((T, int), int) a) { Console.Write(4); }
}";
var comp = CompileAndVerify(source, additionalRefs: s_valueTupleRefs, expectedOutput: "4");
}

[Fact(Skip = "https://github.com/dotnet/roslyn/issues/20583")]
[WorkItem(20494, "https://github.com/dotnet/roslyn/issues/20494")]
[WorkItem(20583, "https://github.com/dotnet/roslyn/issues/20583")]
public void MoreGenericTieBreaker_02()
{
var source =
@"using System;
public class C
{
public static void Main()
{
// var b = (1, 2, 3, 4, 5, 6, 7, 8);
var b = new ValueTuple<int, int, int, int, int, int, int, ValueTuple<int>>(1, 2, 3, 4, 5, 6, 7, new ValueTuple<int>(8));
M1(b);
M2(b); // ok, should select M2<T1, T2, T3, T4, T5, T6, T7, T8>(ValueTuple<T1, T2, T3, T4, T5, T6, T7, ValueTuple<T8>> a)
}
public static void M1<T1, T2, T3, T4, T5, T6, T7, TRest>(ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> a) where TRest : struct { Console.Write(1); }
public static void M2<T1, T2, T3, T4, T5, T6, T7, T8>(ValueTuple<T1, T2, T3, T4, T5, T6, T7, ValueTuple<T8>> a) { Console.Write(2); }
public static void M2<T1, T2, T3, T4, T5, T6, T7, TRest>(ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> a) where TRest : struct { Console.Write(3); }
}
";
var comp = CompileAndVerify(source,
additionalRefs: s_valueTupleRefs,
expectedOutput: @"12");
}

[Fact(Skip = "https://github.com/dotnet/roslyn/issues/20583")]
[WorkItem(20494, "https://github.com/dotnet/roslyn/issues/20494")]
[WorkItem(20583, "https://github.com/dotnet/roslyn/issues/20583")]
public void MoreGenericTieBreaker_02b()
{
var source =
@"using System;
public class C
{
public static void Main()
{
var b = (1, 2, 3, 4, 5, 6, 7, 8);
M1(b);
M2(b); // ok, should select M2<T1, T2, T3, T4, T5, T6, T7, T8>((T1, T2, T3, T4, T5, T6, T7, T8) a)
}
public static void M1<T1, T2, T3, T4, T5, T6, T7, TRest>(ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> a) where TRest : struct { Console.Write(1); }
public static void M2<T1, T2, T3, T4, T5, T6, T7, T8>((T1, T2, T3, T4, T5, T6, T7, T8) a) { Console.Write(2); }
public static void M2<T1, T2, T3, T4, T5, T6, T7, TRest>(ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest> a) where TRest : struct { Console.Write(3); }
}
";
var comp = CompileAndVerify(source,
additionalRefs: s_valueTupleRefs,
expectedOutput: @"12");
}

[Fact]
[WorkItem(20494, "https://github.com/dotnet/roslyn/issues/20494")]
public void MoreGenericTieBreaker_03()
{
var source =
@"using System;
public class C
{
public static void Main()
{
var b = ((1, 1), 2, 3, 4, 5, 6, 7, 8, 9, (10, 10), (11, 11));
M1(b); // ok, should select M2<T, U, V>(((T, int), int, int, int, int, int, int, int, int, (U, int), V) a)
}
public static void M1<T, U, V>(((T, int), int, int, int, int, int, int, int, int, (U, int), V) a)
{ Console.Write(3); }
public static void M1<T, U, V>((T, int, int, int, int, int, int, int, int, U, (V, int)) a)
{ Console.Write(4); }
}";
var comp = CompileAndVerify(source, additionalRefs: s_valueTupleRefs, expectedOutput: "3");
}

[Fact]
[WorkItem(20494, "https://github.com/dotnet/roslyn/issues/20494")]
public void MoreGenericTieBreaker_04()
{
var source =
@"using System;
public class C
{
public static void Main()
{
var b = ((1, 1), 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, (20, 20));
M1(b); // error: ambiguous
}
public static void M1<T, U>((T, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, (U, int)) a)
{ Console.Write(3); }
public static void M1<T, U>(((T, int), int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, U) a)
{ Console.Write(4); }
}";
CreateStandardCompilation(source, references: s_valueTupleRefs).VerifyDiagnostics(
// (7,9): error CS0121: The call is ambiguous between the following methods or properties: 'C.M1<T, U>((T, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, (U, int)))' and 'C.M1<T, U>(((T, int), int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, U))'
// M1(b); // error: ambiguous
Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("C.M1<T, U>((T, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, (U, int)))", "C.M1<T, U>(((T, int), int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, U))").WithLocation(7, 9)
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4532,8 +4532,8 @@ ContinueCandidatesLoop:

' Both are generics
If leftType.Kind = SymbolKind.NamedType AndAlso rightType.Kind = SymbolKind.NamedType Then
Dim leftNamedType = DirectCast(leftType, NamedTypeSymbol)
Dim rightNamedType = DirectCast(rightType, NamedTypeSymbol)
Dim leftNamedType = DirectCast(leftType.GetTupleUnderlyingTypeOrSelf(), NamedTypeSymbol)
Dim rightNamedType = DirectCast(rightType.GetTupleUnderlyingTypeOrSelf(), NamedTypeSymbol)

' If their arities are equal
If leftNamedType.Arity = rightNamedType.Arity Then
Expand Down
128 changes: 128 additions & 0 deletions src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTuples.vb
Original file line number Diff line number Diff line change
Expand Up @@ -20396,6 +20396,134 @@ BC30311: Value of type '(e As Integer?, String)' cannot be converted to '(Intege
Assert.Equal(ConversionKind.DelegateRelaxationLevelNone, model.GetConversion(node).Kind)
End Sub

<Fact>
<WorkItem(20494, "https://github.com/dotnet/roslyn/issues/20494")>
Public Sub MoreGenericTieBreaker_01()
Dim verifier = CompileAndVerify(
<compilation>
<file name="a.vb">
Option Strict On

Imports System
Module Module1
Public Sub Main()
Dim a As A(Of A(Of Integer)) = Nothing
M1(a) ' ok, selects M1(Of T)(A(Of A(Of T)) a)

Dim b = New ValueTuple(Of ValueTuple(Of Integer, Integer), Integer)()
M2(b) ' ok, should select M2(Of T)(ValueTuple(Of ValueTuple(Of T, Integer), Integer) a)
End Sub

Public Sub M1(Of T)(a As A(Of T))
Console.Write(1)
End Sub
Public Sub M1(Of T)(a As A(Of A(Of T)))
Console.Write(2)
End Sub

Public Sub M2(Of T)(a As ValueTuple(Of T, Integer))
Console.Write(3)
End Sub
Public Sub M2(Of T)(a As ValueTuple(Of ValueTuple(Of T, Integer), Integer))
Console.Write(4)
End Sub
End Module

Public Class A(Of T)
End Class
</file>
</compilation>, additionalRefs:=s_valueTupleRefs, expectedOutput:=<![CDATA[
24
]]>)
End Sub

<Fact>
<WorkItem(20494, "https://github.com/dotnet/roslyn/issues/20494")>
Public Sub MoreGenericTieBreaker_01b()
Dim verifier = CompileAndVerify(
<compilation>
<file name="a.vb">
Option Strict On

Imports System
Module Module1
Public Sub Main()
Dim b = ((0, 0), 0)
M2(b) ' ok, should select M2(Of T)(ValueTuple(Of ValueTuple(Of T, Integer), Integer) a)
End Sub

Public Sub M2(Of T)(a As (T, Integer))
Console.Write(3)
End Sub
Public Sub M2(Of T)(a As ((T, Integer), Integer))
Console.Write(4)
End Sub
End Module
</file>
</compilation>, additionalRefs:=s_valueTupleRefs, expectedOutput:=<![CDATA[
4
]]>)
End Sub

<Fact>
<WorkItem(20494, "https://github.com/dotnet/roslyn/issues/20494")>
Public Sub MoreGenericTieBreaker_03()
Dim verifier = CompileAndVerify(
<compilation>
<file name="a.vb">
Option Strict On

Imports System
Module Module1
Public Sub Main()
Dim b = ((1, 1), 2, 3, 4, 5, 6, 7, 8, 9, (10, 10), (11, 11))
M1(b) ' ok, should select M1(Of T, U, V)(a As ((T, Integer), Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, (U, Integer), V))
End Sub

Sub M1(Of T, U, V)(a As ((T, Integer), Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, (U, Integer), V))
Console.Write(3)
End Sub
Sub M1(Of T, U, V)(a As (T, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, U, (V, Integer)))
Console.Write(4)
End Sub
End Module
</file>
</compilation>, additionalRefs:=s_valueTupleRefs, expectedOutput:=<![CDATA[
3
]]>)
End Sub

<Fact>
<WorkItem(20494, "https://github.com/dotnet/roslyn/issues/20494")>
Public Sub MoreGenericTieBreaker_04()
Dim source =
<compilation>
<file name="a.vb">
Option Strict On

Imports System
Module Module1
Public Sub Main()
Dim b = ((1, 1), 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, (20, 20))
M1(b) ' error: ambiguous
End Sub

Sub M1(Of T, U)(a As (T, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, (U, Integer)))
Console.Write(3)
End Sub
Sub M1(Of T, U)(a As ((T, Integer), Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, U))
Console.Write(4)
End Sub
End Module
</file>
</compilation>
Dim comp = CompilationUtils.CreateCompilationWithMscorlibAndVBRuntimeAndReferences(source, additionalRefs:=s_valueTupleRefs)
comp.VerifyDiagnostics(
Diagnostic(ERRID.ERR_NoMostSpecificOverload2, "M1").WithArguments("M1", "
'Public Sub M1(Of (Integer, Integer), Integer)(a As ((Integer, Integer), Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, (Integer, Integer)))': Not most specific.
'Public Sub M1(Of Integer, (Integer, Integer))(a As ((Integer, Integer), Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, (Integer, Integer)))': Not most specific.").WithLocation(7, 9)
)
End Sub
End Class

End Namespace
Expand Down

0 comments on commit 3565c81

Please sign in to comment.