Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure tuple conversions involved into a tuple binary operator are properly lowered. #69934

Merged
merged 1 commit into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,8 @@ private BoundExpression DeferSideEffectingArgumentToTempForTupleEquality(
{
case { ConstantValueOpt: { } }:
return VisitExpression(expr);
case BoundConversion { Conversion: { Kind: ConversionKind.DefaultLiteral } }:
// This conversion can be performed lazily, but need not be saved. It is treated as non-side-effecting.
case BoundConversion { Conversion: { Kind: ConversionKind.DefaultLiteral } }: // This conversion can be performed lazily, but need not be saved. It is treated as non-side-effecting.
case BoundConversion { Conversion.IsTupleConversion: true }: // If we were not able to push this conversion down the tree before getting here, it must be performed early, otherwise it won't be properly lowered by this machinery.
return EvaluateSideEffectingArgumentToTemp(expr, effects, temps);
case BoundConversion { Conversion: { Kind: var conversionKind } conversion } when conversionMustBePerformedOnOriginalExpression(conversionKind):
// Some conversions cannot be performed on a copy of the argument and must be done early.
Expand Down
254 changes: 254 additions & 0 deletions src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenTupleEqualityTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5683,5 +5683,259 @@ class K
var comp = CompileAndVerify(source, expectedOutput: "True");
comp.VerifyDiagnostics();
}

[Fact]
[WorkItem("https://github.com/dotnet/roslyn/issues/66265")]
public void Issue66265_01()
{
var source = @"
class C
{
static void Main()
{
(byte, byte) a = (1, 2);
var eq = ((int, int))a == a;
System.Console.Write(eq ? 1 : 0);
}
}
";

var comp = CompileAndVerify(source, expectedOutput: "1").VerifyDiagnostics();
comp.VerifyIL("C.Main", @"
{
// Code size 70 (0x46)
.maxstack 3
.locals init (System.ValueTuple<int, int> V_0,
byte V_1,
byte V_2,
System.ValueTuple<byte, byte> V_3)
IL_0000: ldc.i4.1
IL_0001: ldc.i4.2
IL_0002: newobj ""System.ValueTuple<byte, byte>..ctor(byte, byte)""
IL_0007: dup
IL_0008: stloc.3
IL_0009: ldloc.3
IL_000a: ldfld ""byte System.ValueTuple<byte, byte>.Item1""
IL_000f: ldloc.3
IL_0010: ldfld ""byte System.ValueTuple<byte, byte>.Item2""
IL_0015: newobj ""System.ValueTuple<int, int>..ctor(int, int)""
IL_001a: stloc.0
IL_001b: dup
IL_001c: ldfld ""byte System.ValueTuple<byte, byte>.Item1""
IL_0021: stloc.1
IL_0022: ldfld ""byte System.ValueTuple<byte, byte>.Item2""
IL_0027: stloc.2
IL_0028: ldloc.0
IL_0029: ldfld ""int System.ValueTuple<int, int>.Item1""
IL_002e: ldloc.1
IL_002f: bne.un.s IL_003c
IL_0031: ldloc.0
IL_0032: ldfld ""int System.ValueTuple<int, int>.Item2""
IL_0037: ldloc.2
IL_0038: ceq
IL_003a: br.s IL_003d
IL_003c: ldc.i4.0
IL_003d: ldc.i4.0
IL_003e: cgt.un
IL_0040: call ""void System.Console.Write(int)""
IL_0045: ret
}
");
}

[Fact]
[WorkItem("https://github.com/dotnet/roslyn/issues/66265")]
public void Issue66265_02()
{
var source = @"
class C
{
static void Main()
{
(int, int) a = (1, 2);
var eq = M1() == a;
System.Console.Write(eq ? 1 : 0);
}

static (byte, byte) M1()
{
System.Console.Write(""M1"");
return (1, 2);
}
}
";

var comp = CompileAndVerify(source, expectedOutput: "M11").VerifyDiagnostics();
comp.VerifyIL("C.Main", @"
{
// Code size 56 (0x38)
.maxstack 3
.locals init (byte V_0,
byte V_1,
System.ValueTuple<int, int> V_2)
IL_0000: ldc.i4.1
IL_0001: ldc.i4.2
IL_0002: newobj ""System.ValueTuple<int, int>..ctor(int, int)""
IL_0007: call ""System.ValueTuple<byte, byte> C.M1()""
IL_000c: dup
IL_000d: ldfld ""byte System.ValueTuple<byte, byte>.Item1""
IL_0012: stloc.0
IL_0013: ldfld ""byte System.ValueTuple<byte, byte>.Item2""
IL_0018: stloc.1
IL_0019: stloc.2
IL_001a: ldloc.0
IL_001b: ldloc.2
IL_001c: ldfld ""int System.ValueTuple<int, int>.Item1""
IL_0021: bne.un.s IL_002e
IL_0023: ldloc.1
IL_0024: ldloc.2
IL_0025: ldfld ""int System.ValueTuple<int, int>.Item2""
IL_002a: ceq
IL_002c: br.s IL_002f
IL_002e: ldc.i4.0
IL_002f: ldc.i4.0
IL_0030: cgt.un
IL_0032: call ""void System.Console.Write(int)""
IL_0037: ret
}
");
}

[Fact]
[WorkItem("https://github.com/dotnet/roslyn/issues/66265")]
public void Issue66265_03()
{
var source = @"
class C
{
static void Main()
{
((byte, byte), byte) a = ((1, 2), 3);
var eq = (((int, int), int))a == a;
System.Console.Write(eq ? 1 : 0);
}
}
";

var comp = CompileAndVerify(source, expectedOutput: "1").VerifyDiagnostics();
comp.VerifyIL("C.Main", @"
{
// Code size 131 (0x83)
.maxstack 3
.locals init (System.ValueTuple<System.ValueTuple<int, int>, int> V_0,
byte V_1,
byte V_2,
byte V_3,
System.ValueTuple<System.ValueTuple<byte, byte>, byte> V_4,
System.ValueTuple<byte, byte> V_5)
IL_0000: ldc.i4.1
IL_0001: ldc.i4.2
IL_0002: newobj ""System.ValueTuple<byte, byte>..ctor(byte, byte)""
IL_0007: ldc.i4.3
IL_0008: newobj ""System.ValueTuple<System.ValueTuple<byte, byte>, byte>..ctor(System.ValueTuple<byte, byte>, byte)""
IL_000d: dup
IL_000e: stloc.s V_4
IL_0010: ldloc.s V_4
IL_0012: ldfld ""System.ValueTuple<byte, byte> System.ValueTuple<System.ValueTuple<byte, byte>, byte>.Item1""
IL_0017: stloc.s V_5
IL_0019: ldloc.s V_5
IL_001b: ldfld ""byte System.ValueTuple<byte, byte>.Item1""
IL_0020: ldloc.s V_5
IL_0022: ldfld ""byte System.ValueTuple<byte, byte>.Item2""
IL_0027: newobj ""System.ValueTuple<int, int>..ctor(int, int)""
IL_002c: ldloc.s V_4
IL_002e: ldfld ""byte System.ValueTuple<System.ValueTuple<byte, byte>, byte>.Item2""
IL_0033: newobj ""System.ValueTuple<System.ValueTuple<int, int>, int>..ctor(System.ValueTuple<int, int>, int)""
IL_0038: stloc.0
IL_0039: dup
IL_003a: ldfld ""System.ValueTuple<byte, byte> System.ValueTuple<System.ValueTuple<byte, byte>, byte>.Item1""
IL_003f: dup
IL_0040: ldfld ""byte System.ValueTuple<byte, byte>.Item1""
IL_0045: stloc.1
IL_0046: ldfld ""byte System.ValueTuple<byte, byte>.Item2""
IL_004b: stloc.2
IL_004c: ldfld ""byte System.ValueTuple<System.ValueTuple<byte, byte>, byte>.Item2""
IL_0051: stloc.3
IL_0052: ldloc.0
IL_0053: ldfld ""System.ValueTuple<int, int> System.ValueTuple<System.ValueTuple<int, int>, int>.Item1""
IL_0058: ldfld ""int System.ValueTuple<int, int>.Item1""
IL_005d: ldloc.1
IL_005e: bne.un.s IL_0079
IL_0060: ldloc.0
IL_0061: ldfld ""System.ValueTuple<int, int> System.ValueTuple<System.ValueTuple<int, int>, int>.Item1""
IL_0066: ldfld ""int System.ValueTuple<int, int>.Item2""
IL_006b: ldloc.2
IL_006c: bne.un.s IL_0079
IL_006e: ldloc.0
IL_006f: ldfld ""int System.ValueTuple<System.ValueTuple<int, int>, int>.Item2""
IL_0074: ldloc.3
IL_0075: ceq
IL_0077: br.s IL_007a
IL_0079: ldc.i4.0
IL_007a: ldc.i4.0
IL_007b: cgt.un
IL_007d: call ""void System.Console.Write(int)""
IL_0082: ret
}
");
}

[Fact]
[WorkItem("https://github.com/dotnet/roslyn/issues/66265")]
public void Issue66265_04()
{
var source = @"
class C
{
static void Main()
{
(byte, byte) a = (1, 2);
(int, int) b = (1, 2);
var eq = a == b;
System.Console.Write(eq ? 1 : 0);
}
}
";

var comp = CompileAndVerify(source, expectedOutput: "1").VerifyDiagnostics();
comp.VerifyIL("C.Main", @"
{
// Code size 61 (0x3d)
.maxstack 4
.locals init (System.ValueTuple<int, int> V_0, //b
byte V_1,
byte V_2,
System.ValueTuple<int, int> V_3)
IL_0000: ldc.i4.1
IL_0001: ldc.i4.2
IL_0002: newobj ""System.ValueTuple<byte, byte>..ctor(byte, byte)""
IL_0007: ldloca.s V_0
IL_0009: ldc.i4.1
IL_000a: ldc.i4.2
IL_000b: call ""System.ValueTuple<int, int>..ctor(int, int)""
IL_0010: dup
IL_0011: ldfld ""byte System.ValueTuple<byte, byte>.Item1""
IL_0016: stloc.1
IL_0017: ldfld ""byte System.ValueTuple<byte, byte>.Item2""
IL_001c: stloc.2
IL_001d: ldloc.0
IL_001e: stloc.3
IL_001f: ldloc.1
IL_0020: ldloc.3
IL_0021: ldfld ""int System.ValueTuple<int, int>.Item1""
IL_0026: bne.un.s IL_0033
IL_0028: ldloc.2
IL_0029: ldloc.3
IL_002a: ldfld ""int System.ValueTuple<int, int>.Item2""
IL_002f: ceq
IL_0031: br.s IL_0034
IL_0033: ldc.i4.0
IL_0034: ldc.i4.0
IL_0035: cgt.un
IL_0037: call ""void System.Console.Write(int)""
IL_003c: ret
}
");
}
}
}