Skip to content

Commit

Permalink
Add another test to C# and VB
Browse files Browse the repository at this point in the history
  • Loading branch information
jcouv committed Nov 26, 2024
1 parent 76391e9 commit 9380ce8
Show file tree
Hide file tree
Showing 2 changed files with 368 additions and 0 deletions.
168 changes: 168 additions & 0 deletions src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenIterators.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5379,5 +5379,173 @@ public static System.Collections.Generic.IEnumerable<int> Produce()
""";
CompileAndVerify(src2, expectedOutput: "True finally True").VerifyDiagnostics();
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76078")]
public void StateAfterMoveNext_YieldReturn_AfterTryFinally()
{
string src = """
var enumerator = C.GetEnumerator(true);
System.Console.Write(enumerator.MoveNext());
System.Console.Write(enumerator.Current);
System.Console.Write(enumerator.MoveNext());
System.Console.Write(enumerator.Current);
enumerator.Dispose();
System.Console.Write(enumerator.MoveNext());
System.Console.Write(enumerator.Current);
class C
{
public static System.Collections.Generic.IEnumerator<string> GetEnumerator(bool b)
{
try
{
yield return " one ";
}
finally
{
System.Console.Write("finally ");
}
yield return " two ";
System.Console.Write("not executed after disposal");
}
}
""";
var verifier = CompileAndVerify(src, expectedOutput: "True one finally True two False two").VerifyDiagnostics();
verifier.VerifyIL("C.<GetEnumerator>d__0.System.Collections.IEnumerator.MoveNext()", """
{
// Code size 132 (0x84)
.maxstack 2
.locals init (bool V_0,
int V_1)
.try
{
IL_0000: ldarg.0
IL_0001: ldfld "int C.<GetEnumerator>d__0.<>1__state"
IL_0006: stloc.1
IL_0007: ldloc.1
IL_0008: switch (
IL_001d,
IL_0042,
IL_0066)
IL_0019: ldc.i4.0
IL_001a: stloc.0
IL_001b: leave.s IL_0082
IL_001d: ldarg.0
IL_001e: ldc.i4.m1
IL_001f: stfld "int C.<GetEnumerator>d__0.<>1__state"
IL_0024: ldarg.0
IL_0025: ldc.i4.s -3
IL_0027: stfld "int C.<GetEnumerator>d__0.<>1__state"
IL_002c: ldarg.0
IL_002d: ldstr " one "
IL_0032: stfld "string C.<GetEnumerator>d__0.<>2__current"
IL_0037: ldarg.0
IL_0038: ldc.i4.1
IL_0039: stfld "int C.<GetEnumerator>d__0.<>1__state"
IL_003e: ldc.i4.1
IL_003f: stloc.0
IL_0040: leave.s IL_0082
IL_0042: ldarg.0
IL_0043: ldc.i4.s -3
IL_0045: stfld "int C.<GetEnumerator>d__0.<>1__state"
IL_004a: ldarg.0
IL_004b: call "void C.<GetEnumerator>d__0.<>m__Finally1()"
IL_0050: ldarg.0
IL_0051: ldstr " two "
IL_0056: stfld "string C.<GetEnumerator>d__0.<>2__current"
IL_005b: ldarg.0
IL_005c: ldc.i4.2
IL_005d: stfld "int C.<GetEnumerator>d__0.<>1__state"
IL_0062: ldc.i4.1
IL_0063: stloc.0
IL_0064: leave.s IL_0082
IL_0066: ldarg.0
IL_0067: ldc.i4.m1
IL_0068: stfld "int C.<GetEnumerator>d__0.<>1__state"
IL_006d: ldstr "not executed after disposal"
IL_0072: call "void System.Console.Write(string)"
IL_0077: ldc.i4.0
IL_0078: stloc.0
IL_0079: leave.s IL_0082
}
fault
{
IL_007b: ldarg.0
IL_007c: call "void C.<GetEnumerator>d__0.Dispose()"
IL_0081: endfinally
}
IL_0082: ldloc.0
IL_0083: ret
}
""");

verifier.VerifyIL("C.<GetEnumerator>d__0.System.IDisposable.Dispose()", """
{
// Code size 35 (0x23)
.maxstack 2
.locals init (int V_0)
IL_0000: ldarg.0
IL_0001: ldfld "int C.<GetEnumerator>d__0.<>1__state"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldc.i4.s -3
IL_000a: beq.s IL_0010
IL_000c: ldloc.0
IL_000d: ldc.i4.1
IL_000e: bne.un.s IL_001a
IL_0010: nop
.try
{
IL_0011: leave.s IL_001a
}
finally
{
IL_0013: ldarg.0
IL_0014: call "void C.<GetEnumerator>d__0.<>m__Finally1()"
IL_0019: endfinally
}
IL_001a: ldarg.0
IL_001b: ldc.i4.s -2
IL_001d: stfld "int C.<GetEnumerator>d__0.<>1__state"
IL_0022: ret
}
""");

// Verify GetEnumerator
string src2 = """
var enumerable = C.Produce();
var enumerator = enumerable.GetEnumerator();
System.Console.Write(enumerator.MoveNext());
System.Console.Write(enumerator.MoveNext());
enumerator.Dispose();
System.Console.Write(object.ReferenceEquals(enumerable, enumerable.GetEnumerator()));
class C
{
public static System.Collections.Generic.IEnumerable<int> Produce()
{
try
{
yield return 42;
}
finally
{
System.Console.Write(" finally ");
}
yield return 43;
System.Console.Write("not executed after disposal");
}
}
""";
CompileAndVerify(src2, expectedOutput: "True finally TrueTrue").VerifyDiagnostics();
}
}
}
200 changes: 200 additions & 0 deletions src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenIterators.vb
Original file line number Diff line number Diff line change
Expand Up @@ -3072,5 +3072,205 @@ End Class

CompileAndVerify(source2, expectedOutput:="True finally True")
End Sub

<Fact, WorkItem("https://github.com/dotnet/roslyn/issues/76078")>
Public Sub StateAfterMoveNext_YieldReturn_AfterTryFinally()
Dim source =
<compilation>
<file name="a.vb">
Imports System
Imports System.Collections.Generic

Module Program
Sub Main()
Dim enumerator = C.GetEnumerator(True)

Console.Write(enumerator.MoveNext())
Console.Write(enumerator.Current)

Console.Write(enumerator.MoveNext())
Console.Write(enumerator.Current)

enumerator.Dispose()

Console.Write(enumerator.MoveNext())
Console.Write(enumerator.Current)
End Sub
End Module

Class C
Public Shared Iterator Function GetEnumerator(b As Boolean) As IEnumerator(Of String)
Try
Yield " one "
Finally
Console.Write("finally ")
End Try

Yield " two "
Console.Write("not executed after disposal")
End Function
End Class
</file>
</compilation>
Dim verifier = CompileAndVerify(source, expectedOutput:="True one finally True two False two")
verifier.VerifyIL("C.VB$StateMachine_1_GetEnumerator.MoveNext()", "
{
// Code size 171 (0xab)
.maxstack 3
.locals init (Boolean V_0,
Integer V_1)
IL_0000: ldarg.0
IL_0001: ldfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer""
IL_0006: stloc.1
IL_0007: ldloc.1
IL_0008: ldc.i4.s -3
IL_000a: sub
IL_000b: switch (
IL_0033,
IL_0028,
IL_0028,
IL_002a,
IL_0033,
IL_0094)
IL_0028: ldc.i4.0
IL_0029: ret
IL_002a: ldarg.0
IL_002b: ldc.i4.m1
IL_002c: dup
IL_002d: stloc.1
IL_002e: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer""
IL_0033: nop
.try
{
IL_0034: ldloc.1
IL_0035: ldc.i4.s -3
IL_0037: beq.s IL_003f
IL_0039: ldloc.1
IL_003a: ldc.i4.1
IL_003b: beq.s IL_0064
IL_003d: br.s IL_004c
IL_003f: ldarg.0
IL_0040: ldc.i4.m1
IL_0041: dup
IL_0042: stloc.1
IL_0043: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer""
IL_0048: ldc.i4.1
IL_0049: stloc.0
IL_004a: leave.s IL_00a9
IL_004c: ldarg.0
IL_004d: ldstr "" one ""
IL_0052: stfld ""C.VB$StateMachine_1_GetEnumerator.$Current As String""
IL_0057: ldarg.0
IL_0058: ldc.i4.1
IL_0059: dup
IL_005a: stloc.1
IL_005b: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer""
IL_0060: ldc.i4.1
IL_0061: stloc.0
IL_0062: leave.s IL_00a9
IL_0064: ldarg.0
IL_0065: ldc.i4.m1
IL_0066: dup
IL_0067: stloc.1
IL_0068: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer""
IL_006d: leave.s IL_007e
}
finally
{
IL_006f: ldloc.1
IL_0070: ldc.i4.0
IL_0071: bge.s IL_007d
IL_0073: ldstr ""finally ""
IL_0078: call ""Sub System.Console.Write(String)""
IL_007d: endfinally
}
IL_007e: ldarg.0
IL_007f: ldstr "" two ""
IL_0084: stfld ""C.VB$StateMachine_1_GetEnumerator.$Current As String""
IL_0089: ldarg.0
IL_008a: ldc.i4.2
IL_008b: dup
IL_008c: stloc.1
IL_008d: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer""
IL_0092: ldc.i4.1
IL_0093: ret
IL_0094: ldarg.0
IL_0095: ldc.i4.m1
IL_0096: dup
IL_0097: stloc.1
IL_0098: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer""
IL_009d: ldstr ""not executed after disposal""
IL_00a2: call ""Sub System.Console.Write(String)""
IL_00a7: ldc.i4.0
IL_00a8: ret
IL_00a9: ldloc.0
IL_00aa: ret
}
")
verifier.VerifyIL("C.VB$StateMachine_1_GetEnumerator.Dispose()", "
{
// Code size 44 (0x2c)
.maxstack 2
.locals init (Integer V_0)
IL_0000: ldarg.0
IL_0001: ldfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer""
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldc.i4.1
IL_0009: bne.un.s IL_0015
IL_000b: ldarg.0
IL_000c: ldc.i4.s -3
IL_000e: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer""
IL_0013: br.s IL_001c
IL_0015: ldarg.0
IL_0016: ldc.i4.m1
IL_0017: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer""
IL_001c: ldarg.0
IL_001d: call ""Function C.VB$StateMachine_1_GetEnumerator.MoveNext() As Boolean""
IL_0022: pop
IL_0023: ldarg.0
IL_0024: ldc.i4.s -2
IL_0026: stfld ""C.VB$StateMachine_1_GetEnumerator.$State As Integer""
IL_002b: ret
}
")

' Verify GetEnumerator
Dim source2 =
<compilation>
<file name="a2.vb">
Imports System
Imports System.Collections.Generic

Module Program
Sub Main()
Dim enumerable = C.Produce()
Dim enumerator = enumerable.GetEnumerator()

Console.Write(enumerator.MoveNext())
Console.Write(enumerator.MoveNext())

enumerator.Dispose()
Console.Write(Object.ReferenceEquals(enumerable, enumerable.GetEnumerator()))
End Sub
End Module

Class C
Public Shared Iterator Function Produce() As IEnumerable(Of Integer)
Try
Yield 42
Finally
Console.Write(" finally ")
End Try

Yield 43
Console.Write("not executed after disposal")
End Function
End Class
</file>
</compilation>

CompileAndVerify(source2, expectedOutput:="True finally TrueTrue")
End Sub
End Class
End Namespace

0 comments on commit 9380ce8

Please sign in to comment.