Skip to content

Commit

Permalink
Add more tests, including the table from https://github.com/dotnet/cs…
Browse files Browse the repository at this point in the history
  • Loading branch information
333fred committed Sep 4, 2024
1 parent 4c80cae commit 1e9b43b
Show file tree
Hide file tree
Showing 2 changed files with 370 additions and 30 deletions.
168 changes: 162 additions & 6 deletions src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1469,6 +1469,16 @@ void verify(CSharpParseOptions parseOptions, string expectedType)
[InlineData("System.Collections.Generic.List<int>", "System.Collections.Generic.IEnumerable<int>", "System.Collections.Generic.List<System.Int32>")]
[InlineData("int[]", "object[]", null)] // rule requires span
[InlineData("int[]", "System.Collections.Generic.IReadOnlyList<object>", null)] // rule requires span
[InlineData("System.Collections.Generic.List<int>", "System.Collections.Generic.List<byte>", null)]
[InlineData("System.Collections.Generic.List<int?>", "System.Collections.Generic.List<long>", null)]
[InlineData("System.Collections.Generic.List<int?>", "System.Collections.Generic.List<ulong>", null)]
[InlineData("System.Collections.Generic.List<short>", "System.Collections.Generic.List<long>", null)]
[InlineData("System.Collections.Generic.IEnumerable<int>", "System.Collections.Generic.List<byte>", null)]
[InlineData("int[]", "System.Collections.Generic.List<byte>", null)]
[InlineData("System.Collections.Generic.HashSet<short>", "System.Span<long>", null)]
[InlineData("System.Collections.Generic.HashSet<short>", "System.ReadOnlySpan<long>", null)]
[InlineData("System.Collections.Generic.HashSet<long>", "System.Span<short>", null)]
[InlineData("System.Collections.Generic.HashSet<long>", "System.ReadOnlySpan<short>", null)]
public void BetterConversionFromExpression_01B_Empty(string type1, string type2, string expectedType)
{
string source = $$"""
Expand Down Expand Up @@ -1558,6 +1568,16 @@ static string generateMethodSignature(string methodName, string parameterType) =
[InlineData("System.Collections.Generic.List<int>", "System.Collections.Generic.IEnumerable<int>", "System.Collections.Generic.List<System.Int32>")]
[InlineData("int[]", "object[]", "System.Int32[]")]
[InlineData("int[]", "System.Collections.Generic.IReadOnlyList<object>", "System.Int32[]")]
[InlineData("System.Collections.Generic.List<int>", "System.Collections.Generic.List<byte>", "System.Collections.Generic.List<System.Int32>")]
[InlineData("System.Collections.Generic.List<int?>", "System.Collections.Generic.List<long>", null)]
[InlineData("System.Collections.Generic.List<int?>", "System.Collections.Generic.List<ulong>", "System.Collections.Generic.List<System.Nullable<System.Int32>>")]
[InlineData("System.Collections.Generic.List<short>", "System.Collections.Generic.List<long>", "System.Collections.Generic.List<System.Int16>")]
[InlineData("System.Collections.Generic.IEnumerable<int>", "System.Collections.Generic.List<byte>", "System.Collections.Generic.IEnumerable<System.Int32>")]
[InlineData("int[]", "System.Collections.Generic.List<byte>", "System.Int32[]")]
[InlineData("System.Collections.Generic.HashSet<short>", "System.Span<long>", "System.Collections.Generic.HashSet<System.Int16>")]
[InlineData("System.Collections.Generic.HashSet<short>", "System.ReadOnlySpan<long>", "System.Collections.Generic.HashSet<System.Int16>")]
[InlineData("System.Collections.Generic.HashSet<long>", "System.Span<short>", "System.Span<System.Int16>")]
[InlineData("System.Collections.Generic.HashSet<long>", "System.ReadOnlySpan<short>", "System.ReadOnlySpan<System.Int16>")]
public void BetterConversionFromExpression_01B_NotEmpty(string type1, string type2, string expectedType)
{
string source = $$"""
Expand All @@ -1582,13 +1602,29 @@ static void Main()
targetFramework: TargetFramework.Net80,
options: TestOptions.ReleaseExe);

CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput($"""
{expectedType}
{expectedType}
"""));
if (expectedType is { })
{
CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput($"""
{expectedType}
{expectedType}
"""));
}
else
{
comp.VerifyEmitDiagnostics(
// 0.cs(10,17): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F1(int[])' and 'Program.F1(object[])'
// var c = F1(1, 2, 3);
Diagnostic(ErrorCode.ERR_AmbigCall, "F1").WithArguments(generateMethodSignature("F1", type1), generateMethodSignature("F1", type2)).WithLocation(10, 17),
// 0.cs(12,17): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F2(object[])' and 'Program.F2(int[])'
// var d = F2(4, 5);
Diagnostic(ErrorCode.ERR_AmbigCall, "F2").WithArguments(generateMethodSignature("F2", type2), generateMethodSignature("F2", type1)).WithLocation(12, 17));
}

static string generateMethod(string methodName, string parameterType) =>
$"static Type {methodName}({parameterType} value) => typeof({parameterType});";

static string generateMethodSignature(string methodName, string parameterType) =>
$"Program.{methodName}({parameterType})";
}

[Theory]
Expand Down Expand Up @@ -1731,19 +1767,31 @@ partial class Program
string source1 = $$"""
var a = F1([]);
var b = F2([]);
var c = F1([$"{1}", $"2", $"{3}"]);
var d = F2([$"{1}", $"2", $"{3}"]);
""";
var comp = CreateCompilation(
[source1, testMethods, customHandler, s_collectionExtensions],
targetFramework: TargetFramework.Net80,
options: TestOptions.ReleaseExe);

string f1InterpolatedSig = generateMethodSignature("F1", interpolatedType);
string f1StringSig = generateMethodSignature("F1", stringType);
string f2InterpolatedSig = generateMethodSignature("F2", interpolatedType);
string f2StringSig = generateMethodSignature("F2", stringType);
comp.VerifyDiagnostics(
// (1,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F1(IReadOnlyList<string>)' and 'Program.F1(IReadOnlyCollection<CustomHandler>)'
// var a = F1([]);
Diagnostic(ErrorCode.ERR_AmbigCall, "F1").WithArguments(generateMethodSignature("F1", stringType), generateMethodSignature("F1", interpolatedType)).WithLocation(1, 9),
Diagnostic(ErrorCode.ERR_AmbigCall, "F1").WithArguments(f1StringSig, f1InterpolatedSig).WithLocation(1, 9),
// (2,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F2(IReadOnlyCollection<CustomHandler>)' and 'Program.F2(IReadOnlyList<string>)'
// var b = F2([]);
Diagnostic(ErrorCode.ERR_AmbigCall, "F2").WithArguments(generateMethodSignature("F2", interpolatedType), generateMethodSignature("F2", stringType)).WithLocation(2, 9)
Diagnostic(ErrorCode.ERR_AmbigCall, "F2").WithArguments(f2InterpolatedSig, f2StringSig).WithLocation(2, 9),
// (3,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F1(string[])' and 'Program.F1(CustomHandler[])'
// var c = F1([$"{1}", $"2", $"{3}"]);
Diagnostic(ErrorCode.ERR_AmbigCall, "F1").WithArguments(f1StringSig, f1InterpolatedSig).WithLocation(3, 9),
// (4,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F2(CustomHandler[])' and 'Program.F2(string[])'
// var d = F2([$"{1}", $"2", $"{3}"]);
Diagnostic(ErrorCode.ERR_AmbigCall, "F2").WithArguments(f2InterpolatedSig, f2StringSig).WithLocation(4, 9)
);

var source2 = $$"""
Expand All @@ -1752,16 +1800,23 @@ partial class Program
Console.WriteLine(c.GetTypeName());
var d = F2([$"{1}", $"{2}", $"{3}"]);
Console.WriteLine(d.GetTypeName());
var e = F1([$"1", $"2", $"3"]);
Console.WriteLine(e.GetTypeName());
var f = F2([$"1", $"2", $"3"]);
Console.WriteLine(f.GetTypeName());
""";

comp = CreateCompilation(
[source2, testMethods, customHandler, s_collectionExtensions],
targetFramework: TargetFramework.Net80,
options: TestOptions.ReleaseExe);

string outputStringType = stringType.Replace("string", "System.String");
CompileAndVerify(comp, verify: Verification.Skipped, expectedOutput: IncludeExpectedOutput($"""
{interpolatedType}
{interpolatedType}
{outputStringType}
{outputStringType}
"""));

static string generateMethod(string methodName, string parameterType) =>
Expand Down Expand Up @@ -2141,6 +2196,107 @@ static void Main()
CompileAndVerify(source, expectedOutput: "string[]");
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73857")]
public void BetterConversionFromExpression_08C()
{
string source = """
using System;
class Program
{
static void F2(ReadOnlySpan<string> value) { Console.WriteLine("ReadOnlySpan<string>"); }
static void F2(ReadOnlySpan<object> value) { Console.WriteLine("ReadOnlySpan<object>"); }
static void Main()
{
F2(["a", "b"]);
}
}
""";
CompileAndVerify(source,
targetFramework: TargetFramework.Net80,
verify: Verification.Skipped,
expectedOutput: IncludeExpectedOutput("ReadOnlySpan<string>"));
}

[Fact]
public void BetterConversionFromExpression_09()
{
string source = """
using System;
using System.Collections.Generic;
class Program
{
static void F2(List<int> value) { Console.WriteLine("List<int>"); }
static void F2(List<byte> value) { Console.WriteLine("List<byte>"); }
static void Main()
{
F2([1, (byte)2]);
}
}
""";

// (9,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F2(List<int>)' and 'Program.F2(List<byte>)'
// F2([1, (byte)2]);
var expected = Diagnostic(ErrorCode.ERR_AmbigCall, "F2").WithArguments("Program.F2(System.Collections.Generic.List<int>)", "Program.F2(System.Collections.Generic.List<byte>)").WithLocation(9, 9);
CreateCompilation(source, parseOptions: TestOptions.Regular13).VerifyDiagnostics(expected);
CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expected);
}

[Fact]
public void BetterConversionFromExpression_10()
{
string source = """
using System;
using System.Collections.Generic;
class Program
{
static void F2(List<int> value) { Console.WriteLine("List<int>"); }
static void F2(List<byte> value) { Console.WriteLine("List<byte>"); }
static void Main()
{
F2([(byte)1, (byte)2]);
}
}
""";

CompileAndVerify(source, parseOptions: TestOptions.Regular13, expectedOutput: "List<byte>");

CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(
// (9,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F2(List<int>)' and 'Program.F2(List<byte>)'
// F2([1, (byte)2]);
Diagnostic(ErrorCode.ERR_AmbigCall, "F2").WithArguments("Program.F2(System.Collections.Generic.List<int>)", "Program.F2(System.Collections.Generic.List<byte>)").WithLocation(9, 9));
}

[Theory]
[InlineData("System.FormattableString")]
[InlineData("System.IFormattable")]
public void BetterConversionFromExpression_11(string formatType)
{
string source = $$"""
using System;
class Program
{
static void F2(ReadOnlySpan<string> value) { Console.WriteLine("ReadOnlySpan<string>"); }
static void F2(ReadOnlySpan<{{formatType}}> value) { Console.WriteLine("ReadOnlySpan<{{formatType}}>"); }
static void Main()
{
F2([$"{1}"]);
}
}
""";

CompileAndVerify(source,
parseOptions: TestOptions.Regular13,
targetFramework: TargetFramework.Net80,
verify: Verification.Skipped,
expectedOutput: IncludeExpectedOutput("ReadOnlySpan<string>"));

CreateCompilation(source, parseOptions: TestOptions.Regular12, targetFramework: TargetFramework.Net80).VerifyDiagnostics(
// (8,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.F2(ReadOnlySpan<string>)' and 'Program.F2(ReadOnlySpan<IFormattable>)'
// F2([$"{1}"]);
Diagnostic(ErrorCode.ERR_AmbigCall, "F2").WithArguments("Program.F2(System.ReadOnlySpan<string>)", $"Program.F2(System.ReadOnlySpan<{formatType}>)").WithLocation(8, 9)
);
}

[Theory]
[InlineData("System.ReadOnlySpan<char>")]
[InlineData("System.Span<char>")]
Expand Down
Loading

0 comments on commit 1e9b43b

Please sign in to comment.