/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenForeach.vb
3 083 строки
84 KB
Tomáš Matoušek
Refactoring of extension methods in source packages (#78620) - take 2 (#78894)
26 июн 2025, 18:42
Не верифицирован
26 июн 2025, 18:42
05fc006
Код
Авторство
О чём код?
' Licensed to the .NET Foundation under one or more agreements. ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. Imports Roslyn.Test.Utilities Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests Public Class CodeGenForeach Inherits BasicTestBase ' The loop object must be an array or an object collection <Fact> Public Sub SimpleForeachTest() Dim compilation1 = CompileAndVerify( <compilation> <file name="a.vb"> Imports System Class C Shared Sub Main() Dim arr As String() = New String(1) {} arr(0) = "one" arr(1) = "two" For Each s As String In arr Console.WriteLine(s) Next End Sub End Class </file> </compilation>, expectedOutput:=<![CDATA[ one two ]]>).VerifyIL("C.Main", <![CDATA[ { // Code size 46 (0x2e) .maxstack 4 .locals init (String() V_0, Integer V_1) IL_0000: ldc.i4.2 IL_0001: newarr "String" IL_0006: dup IL_0007: ldc.i4.0 IL_0008: ldstr "one" IL_000d: stelem.ref IL_000e: dup IL_000f: ldc.i4.1 IL_0010: ldstr "two" IL_0015: stelem.ref IL_0016: stloc.0 IL_0017: ldc.i4.0 IL_0018: stloc.1 IL_0019: br.s IL_0027 IL_001b: ldloc.0 IL_001c: ldloc.1 IL_001d: ldelem.ref IL_001e: call "Sub System.Console.WriteLine(String)" IL_0023: ldloc.1 IL_0024: ldc.i4.1 IL_0025: add.ovf IL_0026: stloc.1 IL_0027: ldloc.1 IL_0028: ldloc.0 IL_0029: ldlen IL_002a: conv.i4 IL_002b: blt.s IL_001b IL_002d: ret } ]]>).Compilation End Sub ' Type is not required in a foreach statement <Fact> Public Sub TypeIsNotRequiredTest() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Infer On Imports System Class C Shared Sub Main() Dim myarray As Integer() = New Integer(2) {1, 2, 3} For Each item In myarray Next End Sub End Class </file> </compilation>, options:=TestOptions.ReleaseExe.WithModuleName("MODULE")).VerifyIL("C.Main", <![CDATA[ { // Code size 37 (0x25) .maxstack 3 .locals init (Integer() V_0, Integer V_1) IL_0000: ldc.i4.3 IL_0001: newarr "Integer" IL_0006: dup IL_0007: ldtoken "<PrivateImplementationDetails>.__StaticArrayInitTypeSize=12 <PrivateImplementationDetails>.4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D" IL_000c: call "Sub System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)" IL_0011: stloc.0 IL_0012: ldc.i4.0 IL_0013: stloc.1 IL_0014: br.s IL_001e IL_0016: ldloc.0 IL_0017: ldloc.1 IL_0018: ldelem.i4 IL_0019: pop IL_001a: ldloc.1 IL_001b: ldc.i4.1 IL_001c: add.ovf IL_001d: stloc.1 IL_001e: ldloc.1 IL_001f: ldloc.0 IL_0020: ldlen IL_0021: conv.i4 IL_0022: blt.s IL_0016 IL_0024: ret } ]]>) End Sub ' Narrowing conversions from the elements in group to element are evaluated and performed at run time <Fact> Public Sub NarrowConversions() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Strict On Imports System Class C Shared Sub Main() For Each number As Integer In New Long() {45, 3} Console.WriteLine(number) Next End Sub End Class </file> </compilation>, expectedOutput:=<![CDATA[ 45 3 ]]>).VerifyIL("C.Main", <![CDATA[ { // Code size 42 (0x2a) .maxstack 4 .locals init (Long() V_0, Integer V_1) IL_0000: ldc.i4.2 IL_0001: newarr "Long" IL_0006: dup IL_0007: ldc.i4.0 IL_0008: ldc.i4.s 45 IL_000a: conv.i8 IL_000b: stelem.i8 IL_000c: dup IL_000d: ldc.i4.1 IL_000e: ldc.i4.3 IL_000f: conv.i8 IL_0010: stelem.i8 IL_0011: stloc.0 IL_0012: ldc.i4.0 IL_0013: stloc.1 IL_0014: br.s IL_0023 IL_0016: ldloc.0 IL_0017: ldloc.1 IL_0018: ldelem.i8 IL_0019: conv.ovf.i4 IL_001a: call "Sub System.Console.WriteLine(Integer)" IL_001f: ldloc.1 IL_0020: ldc.i4.1 IL_0021: add.ovf IL_0022: stloc.1 IL_0023: ldloc.1 IL_0024: ldloc.0 IL_0025: ldlen IL_0026: conv.i4 IL_0027: blt.s IL_0016 IL_0029: ret } ]]>) End Sub ' Narrowing conversions from the elements in group to element are evaluated and performed at run time <Fact> Public Sub NarrowConversions_2() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Strict On Imports System Class C Shared Sub Main() For Each number As Integer In New Long() {9876543210} Console.WriteLine(number) Next End Sub End Class </file> </compilation>, options:=TestOptions.ReleaseExe).VerifyIL("C.Main", <![CDATA[ { // Code size 43 (0x2b) .maxstack 4 .locals init (Long() V_0, Integer V_1) IL_0000: ldc.i4.1 IL_0001: newarr "Long" IL_0006: dup IL_0007: ldc.i4.0 IL_0008: ldc.i8 0x24cb016ea IL_0011: stelem.i8 IL_0012: stloc.0 IL_0013: ldc.i4.0 IL_0014: stloc.1 IL_0015: br.s IL_0024 IL_0017: ldloc.0 IL_0018: ldloc.1 IL_0019: ldelem.i8 IL_001a: conv.ovf.i4 IL_001b: call "Sub System.Console.WriteLine(Integer)" IL_0020: ldloc.1 IL_0021: ldc.i4.1 IL_0022: add.ovf IL_0023: stloc.1 IL_0024: ldloc.1 IL_0025: ldloc.0 IL_0026: ldlen IL_0027: conv.i4 IL_0028: blt.s IL_0017 IL_002a: ret } ]]>) End Sub ' Multiline <Fact> Public Sub Multiline() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Strict On Imports System Class C Shared Public Sub Main() Dim a() As Integer = New Integer() {7} For Each x As Integer In a : System.Console.WriteLine(x) : Next End Sub End Class </file> </compilation>, options:=TestOptions.ReleaseExe).VerifyIL("C.Main", <![CDATA[ { // Code size 34 (0x22) .maxstack 4 .locals init (Integer() V_0, Integer V_1) IL_0000: ldc.i4.1 IL_0001: newarr "Integer" IL_0006: dup IL_0007: ldc.i4.0 IL_0008: ldc.i4.7 IL_0009: stelem.i4 IL_000a: stloc.0 IL_000b: ldc.i4.0 IL_000c: stloc.1 IL_000d: br.s IL_001b IL_000f: ldloc.0 IL_0010: ldloc.1 IL_0011: ldelem.i4 IL_0012: call "Sub System.Console.WriteLine(Integer)" IL_0017: ldloc.1 IL_0018: ldc.i4.1 IL_0019: add.ovf IL_001a: stloc.1 IL_001b: ldloc.1 IL_001c: ldloc.0 IL_001d: ldlen IL_001e: conv.i4 IL_001f: blt.s IL_000f IL_0021: ret } ]]>) End Sub ' Line continuations <Fact> Public Sub LineContinuations() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Strict On Imports System Class C Public Shared Sub Main() Dim a() As Integer = New Integer() {7} For _ Each _ x _ As _ Integer _ In _ a _ _ : Next End Sub End Class </file> </compilation>, options:=TestOptions.ReleaseExe).VerifyIL("C.Main", <![CDATA[ { // Code size 30 (0x1e) .maxstack 4 .locals init (Integer() V_0, Integer V_1) IL_0000: ldc.i4.1 IL_0001: newarr "Integer" IL_0006: dup IL_0007: ldc.i4.0 IL_0008: ldc.i4.7 IL_0009: stelem.i4 IL_000a: stloc.0 IL_000b: ldc.i4.0 IL_000c: stloc.1 IL_000d: br.s IL_0017 IL_000f: ldloc.0 IL_0010: ldloc.1 IL_0011: ldelem.i4 IL_0012: pop IL_0013: ldloc.1 IL_0014: ldc.i4.1 IL_0015: add.ovf IL_0016: stloc.1 IL_0017: ldloc.1 IL_0018: ldloc.0 IL_0019: ldlen IL_001a: conv.i4 IL_001b: blt.s IL_000f IL_001d: ret } ]]>) End Sub <Fact(), WorkItem(9151, "DevDiv_Projects/Roslyn"), WorkItem(546096, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546096")> Public Sub IterationVarInConditionalExpression() CompileAndVerify( <compilation> <file name="a.vb"> Option Strict Off Class C Shared Sub Main() For Each x As S In If(True, x, 1) Next End Sub End Class Public Structure S End Structure </file> </compilation>).VerifyIL("C.Main", <![CDATA[ { // Code size 77 (0x4d) .maxstack 2 .locals init (S V_0, System.Collections.IEnumerator V_1, S V_2) .try { IL_0000: ldloc.0 IL_0001: box "S" IL_0006: castclass "System.Collections.IEnumerable" IL_000b: callvirt "Function System.Collections.IEnumerable.GetEnumerator() As System.Collections.IEnumerator" IL_0010: stloc.1 IL_0011: br.s IL_002e IL_0013: ldloc.1 IL_0014: callvirt "Function System.Collections.IEnumerator.get_Current() As Object" IL_0019: dup IL_001a: brtrue.s IL_0028 IL_001c: pop IL_001d: ldloca.s V_2 IL_001f: initobj "S" IL_0025: ldloc.2 IL_0026: br.s IL_002d IL_0028: unbox.any "S" IL_002d: pop IL_002e: ldloc.1 IL_002f: callvirt "Function System.Collections.IEnumerator.MoveNext() As Boolean" IL_0034: brtrue.s IL_0013 IL_0036: leave.s IL_004c } finally { IL_0038: ldloc.1 IL_0039: isinst "System.IDisposable" IL_003e: brfalse.s IL_004b IL_0040: ldloc.1 IL_0041: isinst "System.IDisposable" IL_0046: callvirt "Sub System.IDisposable.Dispose()" IL_004b: endfinally } IL_004c: ret } ]]>) End Sub ' Use the declared variable to initialize collection <Fact> Public Sub IterationVarInCollectionExpression_1() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Class C Public Shared Sub Main() For Each x As Integer In New Integer() {x + 5, x + 6, x + 7} System.Console.WriteLine(x) Next End Sub End Class </file> </compilation>, expectedOutput:=<![CDATA[ 5 6 7 ]]>) End Sub <Fact(), WorkItem(9151, "DevDiv_Projects/Roslyn"), WorkItem(546096, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546096")> Public Sub TraversingNothing() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Strict Off Class C Shared Sub Main() For Each item In Nothing Next End Sub End Class </file> </compilation>).VerifyIL("C.Main", <![CDATA[ { // Code size 52 (0x34) .maxstack 1 .locals init (System.Collections.IEnumerator V_0) .try { IL_0000: ldnull IL_0001: callvirt "Function System.Collections.IEnumerable.GetEnumerator() As System.Collections.IEnumerator" IL_0006: stloc.0 IL_0007: br.s IL_0015 IL_0009: ldloc.0 IL_000a: callvirt "Function System.Collections.IEnumerator.get_Current() As Object" IL_000f: call "Function System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(Object) As Object" IL_0014: pop IL_0015: ldloc.0 IL_0016: callvirt "Function System.Collections.IEnumerator.MoveNext() As Boolean" IL_001b: brtrue.s IL_0009 IL_001d: leave.s IL_0033 } finally { IL_001f: ldloc.0 IL_0020: isinst "System.IDisposable" IL_0025: brfalse.s IL_0032 IL_0027: ldloc.0 IL_0028: isinst "System.IDisposable" IL_002d: callvirt "Sub System.IDisposable.Dispose()" IL_0032: endfinally } IL_0033: ret } ]]>) End Sub ' Nested ForEach can use a var declared in the outer ForEach <Fact> Public Sub NestedForeach() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Class C Shared Sub Main() Dim c(3)() As Integer For Each x As Integer() In c ReDim x(3) For i As Integer = 0 To 3 x(i) = i Next For Each y As Integer In x System .Console .WriteLine (y) Next Next End Sub End Class </file> </compilation>, expectedOutput:=<![CDATA[ 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 ]]>) End Sub ' Inner foreach loop referencing the outer foreach loop iteration variable <Fact> Public Sub NestedForeach_1() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Class C Public Shared Sub Main() Dim S As String() = New String() {"ABC", "XYZ"} For Each x As String In S For Each y As Char In x System.Console.WriteLine(y) Next Next End Sub End Class </file> </compilation>, expectedOutput:=<![CDATA[ A B C X Y Z ]]>) End Sub ' Foreach value can't be modified in a loop <Fact> Public Sub ModifyIterationValueInLoop() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Imports System.Collections Class C Shared Sub Main() Dim list As New ArrayList() list.Add("One") list.Add("Two") For Each s As String In list s = "a" Next For Each s As String In list System.Console.WriteLine(s) Next End Sub End Class </file> </compilation>, expectedOutput:=<![CDATA[ One Two ]]>) End Sub ' Pass fields as a ref argument for 'foreach iteration variable' <Fact()> Public Sub PassFieldsAsRefArgument() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Class C Public Shared Sub Main() Dim sa As S() = New S(2) {New S With {.I = 1}, New S With {.I = 2}, New S With {.I = 3}} For Each s As S In sa f(s.i) Next For Each s As S In sa System.Console.WriteLine(s.i) Next End Sub Private Shared Sub f(ByRef iref As Integer) iref = 1 End Sub End Class Structure S Public I As integer End Structure </file> </compilation>, expectedOutput:=<![CDATA[ 1 2 3 ]]>) End Sub ' With multidimensional arrays, you can use one loop to iterate through the elements <Fact> Public Sub TraversingMultidimensionalArray() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Class C Public Shared Sub Main() Dim numbers2D(,) As Integer = New Integer (2,1) {} numbers2D(0,0) = 9 numbers2D(0,1) = 99 numbers2D(1,0) = 3 numbers2D(1,1) = 33 numbers2D(2,0) = 5 numbers2D(2,1) = 55 For Each i As Integer In numbers2D System.Console.WriteLine(i) Next End Sub End Class </file> </compilation>, expectedOutput:=<![CDATA[ 9 99 3 33 5 55 ]]>).VerifyIL("C.Main", <![CDATA[ { // Code size 98 (0x62) .maxstack 5 .locals init (System.Collections.IEnumerator V_0) IL_0000: ldc.i4.3 IL_0001: ldc.i4.2 IL_0002: newobj "Integer(*,*)..ctor" IL_0007: dup IL_0008: ldc.i4.0 IL_0009: ldc.i4.0 IL_000a: ldc.i4.s 9 IL_000c: call "Integer(*,*).Set" IL_0011: dup IL_0012: ldc.i4.0 IL_0013: ldc.i4.1 IL_0014: ldc.i4.s 99 IL_0016: call "Integer(*,*).Set" IL_001b: dup IL_001c: ldc.i4.1 IL_001d: ldc.i4.0 IL_001e: ldc.i4.3 IL_001f: call "Integer(*,*).Set" IL_0024: dup IL_0025: ldc.i4.1 IL_0026: ldc.i4.1 IL_0027: ldc.i4.s 33 IL_0029: call "Integer(*,*).Set" IL_002e: dup IL_002f: ldc.i4.2 IL_0030: ldc.i4.0 IL_0031: ldc.i4.5 IL_0032: call "Integer(*,*).Set" IL_0037: dup IL_0038: ldc.i4.2 IL_0039: ldc.i4.1 IL_003a: ldc.i4.s 55 IL_003c: call "Integer(*,*).Set" IL_0041: callvirt "Function System.Array.GetEnumerator() As System.Collections.IEnumerator" IL_0046: stloc.0 IL_0047: br.s IL_0059 IL_0049: ldloc.0 IL_004a: callvirt "Function System.Collections.IEnumerator.get_Current() As Object" IL_004f: call "Function Microsoft.VisualBasic.CompilerServices.Conversions.ToInteger(Object) As Integer" IL_0054: call "Sub System.Console.WriteLine(Integer)" IL_0059: ldloc.0 IL_005a: callvirt "Function System.Collections.IEnumerator.MoveNext() As Boolean" IL_005f: brtrue.s IL_0049 IL_0061: ret } ]]>) End Sub ' Traversing jagged arrays <Fact> Public Sub TraversingJaggedArray() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Class C Public Shared Sub Main() Dim numbers2D As Integer()() = New Integer()() {New Integer() {1, 2}, New Integer() {4, 5, 6}} For Each x As Integer() In numbers2D For Each y As Integer In x System.Console.WriteLine(y) Next Next End Sub End Class </file> </compilation>, expectedOutput:=<![CDATA[ 1 2 4 5 6 ]]>) End Sub ' Optimization to foreach (char c in String) by treating String as a char array <Fact()> Public Sub TraversingString() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Infer On Class C Public Shared Sub Main() Dim str As String = "ABC" For Each x In str System.Console.WriteLine(x) Next For Each var In "goo" If Not var.[GetType]().Equals(GetType(Char)) Then System.Console.WriteLine("False") End If Next End Sub End Class </file> </compilation>, expectedOutput:=<![CDATA[ A B C ]]>) End Sub ' Traversing items in Dictionary <Fact> Public Sub TraversingDictionary() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Infer On Imports System.Collections.Generic Class C Public Shared Sub Main() Dim s As New Dictionary(Of Integer, Integer)() s.Add(1, 2) s.Add(2, 3) s.Add(3, 4) For Each pair In s System .Console .WriteLine (pair.Key) Next For Each pair As KeyValuePair(Of Integer, Integer) In s System .Console .WriteLine (pair.Value ) Next End Sub End Class </file> </compilation>, expectedOutput:=<![CDATA[ 1 2 3 2 3 4 ]]>).VerifyIL("C.Main", <![CDATA[ { // Code size 141 (0x8d) .maxstack 3 .locals init (System.Collections.Generic.Dictionary(Of Integer, Integer) V_0, //s System.Collections.Generic.Dictionary(Of Integer, Integer).Enumerator V_1, System.Collections.Generic.KeyValuePair(Of Integer, Integer) V_2, //pair System.Collections.Generic.Dictionary(Of Integer, Integer).Enumerator V_3, System.Collections.Generic.KeyValuePair(Of Integer, Integer) V_4) //pair IL_0000: newobj "Sub System.Collections.Generic.Dictionary(Of Integer, Integer)..ctor()" IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: ldc.i4.1 IL_0008: ldc.i4.2 IL_0009: callvirt "Sub System.Collections.Generic.Dictionary(Of Integer, Integer).Add(Integer, Integer)" IL_000e: ldloc.0 IL_000f: ldc.i4.2 IL_0010: ldc.i4.3 IL_0011: callvirt "Sub System.Collections.Generic.Dictionary(Of Integer, Integer).Add(Integer, Integer)" IL_0016: ldloc.0 IL_0017: ldc.i4.3 IL_0018: ldc.i4.4 IL_0019: callvirt "Sub System.Collections.Generic.Dictionary(Of Integer, Integer).Add(Integer, Integer)" .try { IL_001e: ldloc.0 IL_001f: callvirt "Function System.Collections.Generic.Dictionary(Of Integer, Integer).GetEnumerator() As System.Collections.Generic.Dictionary(Of Integer, Integer).Enumerator" IL_0024: stloc.1 IL_0025: br.s IL_003b IL_0027: ldloca.s V_1 IL_0029: call "Function System.Collections.Generic.Dictionary(Of Integer, Integer).Enumerator.get_Current() As System.Collections.Generic.KeyValuePair(Of Integer, Integer)" IL_002e: stloc.2 IL_002f: ldloca.s V_2 IL_0031: call "Function System.Collections.Generic.KeyValuePair(Of Integer, Integer).get_Key() As Integer" IL_0036: call "Sub System.Console.WriteLine(Integer)" IL_003b: ldloca.s V_1 IL_003d: call "Function System.Collections.Generic.Dictionary(Of Integer, Integer).Enumerator.MoveNext() As Boolean" IL_0042: brtrue.s IL_0027 IL_0044: leave.s IL_0054 } finally { IL_0046: ldloca.s V_1 IL_0048: constrained. "System.Collections.Generic.Dictionary(Of Integer, Integer).Enumerator" IL_004e: callvirt "Sub System.IDisposable.Dispose()" IL_0053: endfinally } IL_0054: nop .try { IL_0055: ldloc.0 IL_0056: callvirt "Function System.Collections.Generic.Dictionary(Of Integer, Integer).GetEnumerator() As System.Collections.Generic.Dictionary(Of Integer, Integer).Enumerator" IL_005b: stloc.3 IL_005c: br.s IL_0073 IL_005e: ldloca.s V_3 IL_0060: call "Function System.Collections.Generic.Dictionary(Of Integer, Integer).Enumerator.get_Current() As System.Collections.Generic.KeyValuePair(Of Integer, Integer)" IL_0065: stloc.s V_4 IL_0067: ldloca.s V_4 IL_0069: call "Function System.Collections.Generic.KeyValuePair(Of Integer, Integer).get_Value() As Integer" IL_006e: call "Sub System.Console.WriteLine(Integer)" IL_0073: ldloca.s V_3 IL_0075: call "Function System.Collections.Generic.Dictionary(Of Integer, Integer).Enumerator.MoveNext() As Boolean" IL_007a: brtrue.s IL_005e IL_007c: leave.s IL_008c } finally { IL_007e: ldloca.s V_3 IL_0080: constrained. "System.Collections.Generic.Dictionary(Of Integer, Integer).Enumerator" IL_0086: callvirt "Sub System.IDisposable.Dispose()" IL_008b: endfinally } IL_008c: ret } ]]>) End Sub ' Breaking from nested Loops <Fact> Public Sub BreakFromForeach() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Class C Public Shared Sub Main() Dim S As String() = New String() {"ABC", "XYZ"} For Each x As String In S For Each y As Char In x If y = "B"c Then Exit For Else System.Console.WriteLine(y) End If Next Next End Sub End Class </file> </compilation>, expectedOutput:=<![CDATA[ A X Y Z ]]>) End Sub ' Continuing for nested Loops <Fact> Public Sub ContinueInForeach() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Class C Public Shared Sub Main() Dim S As String() = New String() {"ABC", "XYZ"} For Each x As String In S For Each y As Char In x If y = "B"c Then Continue For End If System.Console.WriteLine(y) Next y, x End Sub End Class </file> </compilation>, expectedOutput:=<![CDATA[ A C X Y Z ]]>) End Sub ' Query expression works in foreach <Fact()> Public Sub QueryExpressionInForeach() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Strict Off Option Infer On Imports System Imports System.Collections Imports System.Linq Class C Public Shared Sub Main() For Each x In From w In New Integer() {1, 2, 3} Select z = w.ToString() System.Console.WriteLine(x.ToLower()) Next End Sub End Class </file> </compilation>, options:=TestOptions.ReleaseExe.WithModuleName("MODULE"), references:={LinqAssemblyRef}, expectedOutput:=<![CDATA[ 1 2 3 ]]>).VerifyIL("C.Main", <![CDATA[ { // Code size 103 (0x67) .maxstack 3 .locals init (System.Collections.Generic.IEnumerator(Of String) V_0) .try { IL_0000: ldc.i4.3 IL_0001: newarr "Integer" IL_0006: dup IL_0007: ldtoken "<PrivateImplementationDetails>.__StaticArrayInitTypeSize=12 <PrivateImplementationDetails>.4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D" IL_000c: call "Sub System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)" IL_0011: ldsfld "C._Closure$__.$I1-0 As System.Func(Of Integer, String)" IL_0016: brfalse.s IL_001f IL_0018: ldsfld "C._Closure$__.$I1-0 As System.Func(Of Integer, String)" IL_001d: br.s IL_0035 IL_001f: ldsfld "C._Closure$__.$I As C._Closure$__" IL_0024: ldftn "Function C._Closure$__._Lambda$__1-0(Integer) As String" IL_002a: newobj "Sub System.Func(Of Integer, String)..ctor(Object, System.IntPtr)" IL_002f: dup IL_0030: stsfld "C._Closure$__.$I1-0 As System.Func(Of Integer, String)" IL_0035: call "Function System.Linq.Enumerable.Select(Of Integer, String)(System.Collections.Generic.IEnumerable(Of Integer), System.Func(Of Integer, String)) As System.Collections.Generic.IEnumerable(Of String)" IL_003a: callvirt "Function System.Collections.Generic.IEnumerable(Of String).GetEnumerator() As System.Collections.Generic.IEnumerator(Of String)" IL_003f: stloc.0 IL_0040: br.s IL_0052 IL_0042: ldloc.0 IL_0043: callvirt "Function System.Collections.Generic.IEnumerator(Of String).get_Current() As String" IL_0048: callvirt "Function String.ToLower() As String" IL_004d: call "Sub System.Console.WriteLine(String)" IL_0052: ldloc.0 IL_0053: callvirt "Function System.Collections.IEnumerator.MoveNext() As Boolean" IL_0058: brtrue.s IL_0042 IL_005a: leave.s IL_0066 } finally { IL_005c: ldloc.0 IL_005d: brfalse.s IL_0065 IL_005f: ldloc.0 IL_0060: callvirt "Sub System.IDisposable.Dispose()" IL_0065: endfinally } IL_0066: ret } ]]>) End Sub ' No confusion in a foreach statement when from is a value type <Fact> Public Sub ReDimFrom() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Infer On Class C Public Shared Sub Main() Dim src = New System.Collections.ArrayList() src.Add(new from(1)) For Each x As from In src System.Console.WriteLine(x.X) Next End Sub End Class Public Structure from Dim X As Integer Public Sub New(p as integer) x = p End Sub End Structure </file> </compilation>, expectedOutput:=<![CDATA[ 1 ]]>) End Sub ' Foreach on generic type that implements the Collection Pattern <Fact> Public Sub GenericTypeImplementsCollection() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Infer On Imports System.Collections.Generic Class C Public Shared Sub Main() For Each j In New Gen(Of Integer)() Next End Sub End Class Public Class Gen(Of T As New) Public Function GetEnumerator() As IEnumerator(Of T) Return Nothing End Function End Class </file> </compilation>, options:=TestOptions.ReleaseExe).VerifyIL("C.Main", <![CDATA[ { // Code size 41 (0x29) .maxstack 1 .locals init (System.Collections.Generic.IEnumerator(Of Integer) V_0) .try { IL_0000: newobj "Sub Gen(Of Integer)..ctor()" IL_0005: call "Function Gen(Of Integer).GetEnumerator() As System.Collections.Generic.IEnumerator(Of Integer)" IL_000a: stloc.0 IL_000b: br.s IL_0014 IL_000d: ldloc.0 IL_000e: callvirt "Function System.Collections.Generic.IEnumerator(Of Integer).get_Current() As Integer" IL_0013: pop IL_0014: ldloc.0 IL_0015: callvirt "Function System.Collections.IEnumerator.MoveNext() As Boolean" IL_001a: brtrue.s IL_000d IL_001c: leave.s IL_0028 } finally { IL_001e: ldloc.0 IL_001f: brfalse.s IL_0027 IL_0021: ldloc.0 IL_0022: callvirt "Sub System.IDisposable.Dispose()" IL_0027: endfinally } IL_0028: ret } ]]>) End Sub ' Customer defined type of collection to support 'foreach' <Fact> Public Sub CustomerDefinedCollections() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Imports System Class C Public Shared Sub Main() Dim col As New MyCollection() For Each i As Integer In col Console.WriteLine(i) Next End Sub End Class Public Class MyCollection Private items As Integer() Public Sub New() items = New Integer(4) {1, 4, 3, 2, 5} End Sub Public Function GetEnumerator() As MyEnumerator Return New MyEnumerator(Me) End Function Public Class MyEnumerator Private nIndex As Integer Private collection As MyCollection Public Sub New(coll As MyCollection) collection = coll nIndex = nIndex - 1 End Sub Public Function MoveNext() As Boolean nIndex = nIndex + 1 Return (nIndex < collection.items.GetLength(0)) End Function Public ReadOnly Property Current() As Integer Get Return (collection.items(nIndex)) End Get End Property End Class End Class </file> </compilation>, expectedOutput:=<![CDATA[ 1 4 3 2 5 ]]>).VerifyIL("C.Main", <![CDATA[ { // Code size 33 (0x21) .maxstack 1 .locals init (MyCollection.MyEnumerator V_0) IL_0000: newobj "Sub MyCollection..ctor()" IL_0005: callvirt "Function MyCollection.GetEnumerator() As MyCollection.MyEnumerator" IL_000a: stloc.0 IL_000b: br.s IL_0018 IL_000d: ldloc.0 IL_000e: callvirt "Function MyCollection.MyEnumerator.get_Current() As Integer" IL_0013: call "Sub System.Console.WriteLine(Integer)" IL_0018: ldloc.0 IL_0019: callvirt "Function MyCollection.MyEnumerator.MoveNext() As Boolean" IL_001e: brtrue.s IL_000d IL_0020: ret } ]]>) End Sub <Fact> Public Sub TestForEachPattern() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Infer On Class C Public Shared Sub Main() For Each x In New Enumerable() System.Console.WriteLine(x) Next End Sub End Class Class Enumerable Public Function GetEnumerator() As Enumerator Return New Enumerator() End Function End Class Class Enumerator Private x As Integer = 0 Public ReadOnly Property Current() As Integer Get Return x End Get End Property Public Function MoveNext() As Boolean Return System.Threading.Interlocked.Increment(x) < 4 End Function End Class </file> </compilation>, expectedOutput:=<![CDATA[ 1 2 3 ]]>).VerifyIL("C.Main", <![CDATA[ { // Code size 33 (0x21) .maxstack 1 .locals init (Enumerator V_0) IL_0000: newobj "Sub Enumerable..ctor()" IL_0005: call "Function Enumerable.GetEnumerator() As Enumerator" IL_000a: stloc.0 IL_000b: br.s IL_0018 IL_000d: ldloc.0 IL_000e: callvirt "Function Enumerator.get_Current() As Integer" IL_0013: call "Sub System.Console.WriteLine(Integer)" IL_0018: ldloc.0 IL_0019: callvirt "Function Enumerator.MoveNext() As Boolean" IL_001e: brtrue.s IL_000d IL_0020: ret } ]]>) End Sub <Fact> Public Sub TestForEachInterface() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Infer On Class C Public Shared Sub Main() For Each x In New Enumerable() System.Console.WriteLine(x) Next End Sub End Class Class Enumerable Implements System.Collections.IEnumerable ' Explicit implementation won't match pattern. Private Function System_Collections_IEnumerable_GetEnumerator() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator Dim list As New System.Collections.Generic.List(Of Integer)() list.Add(3) list.Add(2) list.Add(1) Return list.GetEnumerator() End Function End Class </file> </compilation>, expectedOutput:=<![CDATA[ 3 2 1 ]]>).VerifyIL("C.Main", <![CDATA[ { // Code size 65 (0x41) .maxstack 1 .locals init (System.Collections.IEnumerator V_0) .try { IL_0000: newobj "Sub Enumerable..ctor()" IL_0005: callvirt "Function System.Collections.IEnumerable.GetEnumerator() As System.Collections.IEnumerator" IL_000a: stloc.0 IL_000b: br.s IL_0022 IL_000d: ldloc.0 IL_000e: callvirt "Function System.Collections.IEnumerator.get_Current() As Object" IL_0013: call "Function System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(Object) As Object" IL_0018: call "Function System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(Object) As Object" IL_001d: call "Sub System.Console.WriteLine(Object)" IL_0022: ldloc.0 IL_0023: callvirt "Function System.Collections.IEnumerator.MoveNext() As Boolean" IL_0028: brtrue.s IL_000d IL_002a: leave.s IL_0040 } finally { IL_002c: ldloc.0 IL_002d: isinst "System.IDisposable" IL_0032: brfalse.s IL_003f IL_0034: ldloc.0 IL_0035: isinst "System.IDisposable" IL_003a: callvirt "Sub System.IDisposable.Dispose()" IL_003f: endfinally } IL_0040: ret } ]]>) End Sub <Fact> Public Sub TestForEachExplicitlyDisposableStruct() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Infer On Class C Public Shared Sub Main() For Each x In New Enumerable() System.Console.WriteLine(x) Next End Sub End Class Class Enumerable Public Function GetEnumerator() As Enumerator Return New Enumerator() End Function End Class Structure Enumerator Implements System.IDisposable Private x As Integer Public ReadOnly Property Current() As Integer Get Return x End Get End Property Public Function MoveNext() As Boolean Return System.Threading.Interlocked.Increment(x) < 4 End Function Private Sub System_IDisposable_Dispose() Implements System.IDisposable.Dispose End Sub End Structure </file> </compilation>, expectedOutput:=<![CDATA[ 1 2 3 ]]>).VerifyIL("C.Main", <![CDATA[ { // Code size 51 (0x33) .maxstack 1 .locals init (Enumerator V_0) .try { IL_0000: newobj "Sub Enumerable..ctor()" IL_0005: call "Function Enumerable.GetEnumerator() As Enumerator" IL_000a: stloc.0 IL_000b: br.s IL_0019 IL_000d: ldloca.s V_0 IL_000f: call "Function Enumerator.get_Current() As Integer" IL_0014: call "Sub System.Console.WriteLine(Integer)" IL_0019: ldloca.s V_0 IL_001b: call "Function Enumerator.MoveNext() As Boolean" IL_0020: brtrue.s IL_000d IL_0022: leave.s IL_0032 } finally { IL_0024: ldloca.s V_0 IL_0026: constrained. "Enumerator" IL_002c: callvirt "Sub System.IDisposable.Dispose()" IL_0031: endfinally } IL_0032: ret } ]]>) End Sub <Fact> Public Sub TestForEachDisposeStruct() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Infer On Class C Public Shared Sub Main() For Each x In New Enumerable() System.Console.WriteLine(x) Next End Sub End Class Class Enumerable Public Function GetEnumerator() As Enumerator Return New Enumerator() End Function End Class Structure Enumerator Private x As Integer Public ReadOnly Property Current() As Integer Get Return x End Get End Property Public Function MoveNext() As Boolean Return System.Threading.Interlocked.Increment(x) < 4 End Function Public Sub Dispose() End Sub End Structure </file> </compilation>, expectedOutput:=<![CDATA[ 1 2 3 ]]>).VerifyIL("C.Main", <![CDATA[ { // Code size 35 (0x23) .maxstack 1 .locals init (Enumerator V_0) IL_0000: newobj "Sub Enumerable..ctor()" IL_0005: call "Function Enumerable.GetEnumerator() As Enumerator" IL_000a: stloc.0 IL_000b: br.s IL_0019 IL_000d: ldloca.s V_0 IL_000f: call "Function Enumerator.get_Current() As Integer" IL_0014: call "Sub System.Console.WriteLine(Integer)" IL_0019: ldloca.s V_0 IL_001b: call "Function Enumerator.MoveNext() As Boolean" IL_0020: brtrue.s IL_000d IL_0022: ret } ]]>) End Sub <Fact> Public Sub TestForEachNonDisposableStruct() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Infer On Class C Public Shared Sub Main() For Each x In New Enumerable() System.Console.WriteLine(x) Next End Sub End Class Class Enumerable Public Function GetEnumerator() As Enumerator Return New Enumerator() End Function End Class Structure Enumerator Private x As Integer Public ReadOnly Property Current() As Integer Get Return x End Get End Property Public Function MoveNext() As Boolean Return System.Threading.Interlocked.Increment(x) < 4 End Function End Structure </file> </compilation>, expectedOutput:=<![CDATA[ 1 2 3 ]]>).VerifyIL("C.Main", <![CDATA[ { // Code size 35 (0x23) .maxstack 1 .locals init (Enumerator V_0) IL_0000: newobj "Sub Enumerable..ctor()" IL_0005: call "Function Enumerable.GetEnumerator() As Enumerator" IL_000a: stloc.0 IL_000b: br.s IL_0019 IL_000d: ldloca.s V_0 IL_000f: call "Function Enumerator.get_Current() As Integer" IL_0014: call "Sub System.Console.WriteLine(Integer)" IL_0019: ldloca.s V_0 IL_001b: call "Function Enumerator.MoveNext() As Boolean" IL_0020: brtrue.s IL_000d IL_0022: ret } ]]>) End Sub <Fact> Public Sub TestForEachExplicitlyGetEnumeratorStruct() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Infer On Imports System.Collections Class C Public Shared Sub Main() For Each x In New Enumerable() System.Console.WriteLine(x) Next End Sub End Class Structure Enumerable Implements IEnumerable Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator Return New Integer() {1, 2, 3}.GetEnumerator() End Function End Structure </file> </compilation>, expectedOutput:=<![CDATA[ 1 2 3 ]]>).VerifyIL("C.Main", <![CDATA[ { // Code size 79 (0x4f) .maxstack 1 .locals init (System.Collections.IEnumerator V_0, Enumerable V_1) .try { IL_0000: ldloca.s V_1 IL_0002: initobj "Enumerable" IL_0008: ldloc.1 IL_0009: box "Enumerable" IL_000e: castclass "System.Collections.IEnumerable" IL_0013: callvirt "Function System.Collections.IEnumerable.GetEnumerator() As System.Collections.IEnumerator" IL_0018: stloc.0 IL_0019: br.s IL_0030 IL_001b: ldloc.0 IL_001c: callvirt "Function System.Collections.IEnumerator.get_Current() As Object" IL_0021: call "Function System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(Object) As Object" IL_0026: call "Function System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(Object) As Object" IL_002b: call "Sub System.Console.WriteLine(Object)" IL_0030: ldloc.0 IL_0031: callvirt "Function System.Collections.IEnumerator.MoveNext() As Boolean" IL_0036: brtrue.s IL_001b IL_0038: leave.s IL_004e } finally { IL_003a: ldloc.0 IL_003b: isinst "System.IDisposable" IL_0040: brfalse.s IL_004d IL_0042: ldloc.0 IL_0043: isinst "System.IDisposable" IL_0048: callvirt "Sub System.IDisposable.Dispose()" IL_004d: endfinally } IL_004e: ret } ]]>) End Sub <Fact> Public Sub TestForEachGetEnumeratorStruct() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Infer On Imports System.Collections Class C Public Shared Sub Main() For Each x In New Enumerable() System.Console.WriteLine(x) Next End Sub End Class Structure Enumerable Public Function GetEnumerator() As IEnumerator Return New Integer() {1, 2, 3}.GetEnumerator() End Function End Structure </file> </compilation>, expectedOutput:=<![CDATA[ 1 2 3 ]]>).VerifyIL("C.Main", <![CDATA[ { // Code size 72 (0x48) .maxstack 1 .locals init (System.Collections.IEnumerator V_0, Enumerable V_1) .try { IL_0000: ldloca.s V_1 IL_0002: initobj "Enumerable" IL_0008: ldloc.1 IL_0009: stloc.1 IL_000a: ldloca.s V_1 IL_000c: call "Function Enumerable.GetEnumerator() As System.Collections.IEnumerator" IL_0011: stloc.0 IL_0012: br.s IL_0029 IL_0014: ldloc.0 IL_0015: callvirt "Function System.Collections.IEnumerator.get_Current() As Object" IL_001a: call "Function System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(Object) As Object" IL_001f: call "Function System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(Object) As Object" IL_0024: call "Sub System.Console.WriteLine(Object)" IL_0029: ldloc.0 IL_002a: callvirt "Function System.Collections.IEnumerator.MoveNext() As Boolean" IL_002f: brtrue.s IL_0014 IL_0031: leave.s IL_0047 } finally { IL_0033: ldloc.0 IL_0034: isinst "System.IDisposable" IL_0039: brfalse.s IL_0046 IL_003b: ldloc.0 IL_003c: isinst "System.IDisposable" IL_0041: callvirt "Sub System.IDisposable.Dispose()" IL_0046: endfinally } IL_0047: ret } ]]>) End Sub <Fact> Public Sub TestForEachDisposableSealed() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Infer On Class Enumerable Public Function GetEnumerator() As Enumerator Return New Enumerator() End Function End Class NotInheritable Class Enumerator Implements System.IDisposable Private x As Integer Public ReadOnly Property Current() As Integer Get Return x End Get End Property Public Function MoveNext() As Boolean Return System.Threading.Interlocked.Increment(x) < 4 End Function Private Sub System_IDisposable_Dispose() Implements System.IDisposable.Dispose End Sub End Class Class C Public Shared Sub Main() For Each x In New Enumerable() System.Console.WriteLine(x) Next End Sub End Class </file> </compilation>, expectedOutput:=<![CDATA[ 1 2 3 ]]>).VerifyIL("C.Main", <![CDATA[ { // Code size 45 (0x2d) .maxstack 1 .locals init (Enumerator V_0) .try { IL_0000: newobj "Sub Enumerable..ctor()" IL_0005: call "Function Enumerable.GetEnumerator() As Enumerator" IL_000a: stloc.0 IL_000b: br.s IL_0018 IL_000d: ldloc.0 IL_000e: callvirt "Function Enumerator.get_Current() As Integer" IL_0013: call "Sub System.Console.WriteLine(Integer)" IL_0018: ldloc.0 IL_0019: callvirt "Function Enumerator.MoveNext() As Boolean" IL_001e: brtrue.s IL_000d IL_0020: leave.s IL_002c } finally { IL_0022: ldloc.0 IL_0023: brfalse.s IL_002b IL_0025: ldloc.0 IL_0026: callvirt "Sub System.IDisposable.Dispose()" IL_002b: endfinally } IL_002c: ret } ]]>) End Sub <Fact> Public Sub TestForEachNonDisposableSealed() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Infer On Class C Public Shared Sub Main() For Each x In New Enumerable() System.Console.WriteLine(x) Next End Sub End Class Class Enumerable Public Function GetEnumerator() As Enumerator Return New Enumerator() End Function End Class NotInheritable Class Enumerator Private x As Integer Public ReadOnly Property Current() As Integer Get Return x End Get End Property Public Function MoveNext() As Boolean Return System.Threading.Interlocked.Increment(x) < 4 End Function End Class </file> </compilation>, expectedOutput:=<![CDATA[ 1 2 3 ]]>).VerifyIL("C.Main", <![CDATA[ { // Code size 33 (0x21) .maxstack 1 .locals init (Enumerator V_0) IL_0000: newobj "Sub Enumerable..ctor()" IL_0005: call "Function Enumerable.GetEnumerator() As Enumerator" IL_000a: stloc.0 IL_000b: br.s IL_0018 IL_000d: ldloc.0 IL_000e: callvirt "Function Enumerator.get_Current() As Integer" IL_0013: call "Sub System.Console.WriteLine(Integer)" IL_0018: ldloc.0 IL_0019: callvirt "Function Enumerator.MoveNext() As Boolean" IL_001e: brtrue.s IL_000d IL_0020: ret } ]]>) End Sub <Fact> Public Sub TestForEachNonDisposableAbstractClass() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Infer On Class C Public Shared Sub Main() For Each x In New Enumerable1() System.Console.WriteLine(x) Next For Each x In New Enumerable2() System.Console.WriteLine(x) Next End Sub End Class Class Enumerable1 Public Function GetEnumerator() As AbstractEnumerator Return New DisposableEnumerator() End Function End Class Class Enumerable2 Public Function GetEnumerator() As AbstractEnumerator Return New NonDisposableEnumerator() End Function End Class MustInherit Class AbstractEnumerator Public MustOverride ReadOnly Property Current() As Integer Public MustOverride Function MoveNext() As Boolean End Class Class DisposableEnumerator Inherits AbstractEnumerator Implements System.IDisposable Private x As Integer Public Overrides ReadOnly Property Current() As Integer Get Return x End Get End Property Public Overrides Function MoveNext() As Boolean Return System.Threading.Interlocked.Increment(x) < 4 End Function Private Sub System_IDisposable_Dispose() Implements System.IDisposable.Dispose System.Console.WriteLine("Done with DisposableEnumerator") End Sub End Class Class NonDisposableEnumerator Inherits AbstractEnumerator Private x As Integer Public Overrides ReadOnly Property Current() As Integer Get Return x End Get End Property Public Overrides Function MoveNext() As Boolean Return System.Threading.Interlocked.Decrement(x) > -4 End Function End Class </file> </compilation>, expectedOutput:=<![CDATA[ 1 2 3 -1 -2 -3 ]]>).VerifyIL("C.Main", <![CDATA[ { // Code size 65 (0x41) .maxstack 1 .locals init (AbstractEnumerator V_0, AbstractEnumerator V_1) IL_0000: newobj "Sub Enumerable1..ctor()" IL_0005: call "Function Enumerable1.GetEnumerator() As AbstractEnumerator" IL_000a: stloc.0 IL_000b: br.s IL_0018 IL_000d: ldloc.0 IL_000e: callvirt "Function AbstractEnumerator.get_Current() As Integer" IL_0013: call "Sub System.Console.WriteLine(Integer)" IL_0018: ldloc.0 IL_0019: callvirt "Function AbstractEnumerator.MoveNext() As Boolean" IL_001e: brtrue.s IL_000d IL_0020: newobj "Sub Enumerable2..ctor()" IL_0025: call "Function Enumerable2.GetEnumerator() As AbstractEnumerator" IL_002a: stloc.1 IL_002b: br.s IL_0038 IL_002d: ldloc.1 IL_002e: callvirt "Function AbstractEnumerator.get_Current() As Integer" IL_0033: call "Sub System.Console.WriteLine(Integer)" IL_0038: ldloc.1 IL_0039: callvirt "Function AbstractEnumerator.MoveNext() As Boolean" IL_003e: brtrue.s IL_002d IL_0040: ret } ]]>) End Sub <WorkItem(528679, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/528679")> <Fact> Public Sub TestForEachNested() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Infer on Class C Public Shared Sub Main() For Each x In New Enumerable() For Each y In New Enumerable() System.Console.WriteLine("({0}, {1})", x, y) Next Next End Sub End Class Class Enumerable Public Function GetEnumerator() As Enumerator Return New Enumerator() End Function End Class Class Enumerator Private x As Integer = 0 Public ReadOnly Property Current() As Integer Get Return x End Get End Property Public Function MoveNext() As Boolean Return System.Threading.Interlocked.Increment(x) < 4 End Function End Class </file> </compilation>, expectedOutput:=<![CDATA[ (1, 1) (1, 2) (1, 3) (2, 1) (2, 2) (2, 3) (3, 1) (3, 2) (3, 3) ]]>).VerifyIL("C.Main", <![CDATA[ { // Code size 79 (0x4f) .maxstack 3 .locals init (Enumerator V_0, Integer V_1, //x Enumerator V_2, Integer V_3) //y IL_0000: newobj "Sub Enumerable..ctor()" IL_0005: call "Function Enumerable.GetEnumerator() As Enumerator" IL_000a: stloc.0 IL_000b: br.s IL_0046 IL_000d: ldloc.0 IL_000e: callvirt "Function Enumerator.get_Current() As Integer" IL_0013: stloc.1 IL_0014: newobj "Sub Enumerable..ctor()" IL_0019: call "Function Enumerable.GetEnumerator() As Enumerator" IL_001e: stloc.2 IL_001f: br.s IL_003e IL_0021: ldloc.2 IL_0022: callvirt "Function Enumerator.get_Current() As Integer" IL_0027: stloc.3 IL_0028: ldstr "({0}, {1})" IL_002d: ldloc.1 IL_002e: box "Integer" IL_0033: ldloc.3 IL_0034: box "Integer" IL_0039: call "Sub System.Console.WriteLine(String, Object, Object)" IL_003e: ldloc.2 IL_003f: callvirt "Function Enumerator.MoveNext() As Boolean" IL_0044: brtrue.s IL_0021 IL_0046: ldloc.0 IL_0047: callvirt "Function Enumerator.MoveNext() As Boolean" IL_004c: brtrue.s IL_000d IL_004e: ret } ]]>) End Sub <WorkItem(542075, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542075")> <Fact> Public Sub TestGetEnumeratorWithParams() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Infer On Imports System.Collections.Generic Imports System Class C public Shared Sub Main() For Each x In New B() Console.WriteLine(x.ToLower()) Next End Sub End Class Class A Public Function GetEnumerator() As List(Of String).Enumerator Dim s = New List(Of String)() s.Add("A") s.Add("B") s.Add("C") Return s.GetEnumerator() End Function End Class Class B Inherits A Public Overloads Function GetEnumerator(ParamArray x As Integer()) As List(Of Integer).Enumerator Return nothing End Function End Class </file> </compilation>, expectedOutput:=<![CDATA[ a b c ]]>).VerifyIL("C.Main", <![CDATA[ { // Code size 56 (0x38) .maxstack 1 .locals init (System.Collections.Generic.List(Of String).Enumerator V_0) .try { IL_0000: newobj "Sub B..ctor()" IL_0005: call "Function A.GetEnumerator() As System.Collections.Generic.List(Of String).Enumerator" IL_000a: stloc.0 IL_000b: br.s IL_001e IL_000d: ldloca.s V_0 IL_000f: call "Function System.Collections.Generic.List(Of String).Enumerator.get_Current() As String" IL_0014: callvirt "Function String.ToLower() As String" IL_0019: call "Sub System.Console.WriteLine(String)" IL_001e: ldloca.s V_0 IL_0020: call "Function System.Collections.Generic.List(Of String).Enumerator.MoveNext() As Boolean" IL_0025: brtrue.s IL_000d IL_0027: leave.s IL_0037 } finally { IL_0029: ldloca.s V_0 IL_002b: constrained. "System.Collections.Generic.List(Of String).Enumerator" IL_0031: callvirt "Sub System.IDisposable.Dispose()" IL_0036: endfinally } IL_0037: ret } ]]>) End Sub <Fact> Public Sub TestMoveNextWithNonBoolDeclaredReturnType() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Infer On Imports System.Collections Class Program Public Shared Sub Main() Goo(sub(x) For Each y In x Next end sub ) End Sub Public Shared Sub Goo(a As System.Action(Of IEnumerable)) System.Console.WriteLine(1) End Sub End Class Class A Public Function GetEnumerator() As E(Of Boolean) Return New E(Of Boolean)() End Function End Class Class E(Of T) Public Function MoveNext() As T Return Nothing End Function Public Property Current() As Integer Get Return m_Current End Get Set(value As Integer) m_Current = Value End Set End Property Private m_Current As Integer End Class </file> </compilation>, expectedOutput:=<![CDATA[ 1 ]]>) End Sub <Fact()> Public Sub TestNonConstantNullInForeach() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Infer On Class Program Public Shared Sub Main() Try Const s As String = Nothing For Each y In TryCast(s, String) Next Catch generatedExceptionName As System.NullReferenceException System.Console.WriteLine(1) End Try End Sub End Class </file> </compilation>, expectedOutput:=<![CDATA[ 1 ]]>) End Sub <WorkItem(542079, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542079")> <Fact> Public Sub TestForEachStructEnumerable() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Infer On Imports System.Collections Class C public Shared Sub Main() For Each x In New Enumerable() System.Console.WriteLine(x) Next End Sub End Class Structure Enumerable Implements IEnumerable Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator Return New Integer() {1, 2, 3}.GetEnumerator() End Function End Structure </file> </compilation>, expectedOutput:=<![CDATA[ 1 2 3 ]]>).VerifyIL("C.Main", <![CDATA[ { // Code size 79 (0x4f) .maxstack 1 .locals init (System.Collections.IEnumerator V_0, Enumerable V_1) .try { IL_0000: ldloca.s V_1 IL_0002: initobj "Enumerable" IL_0008: ldloc.1 IL_0009: box "Enumerable" IL_000e: castclass "System.Collections.IEnumerable" IL_0013: callvirt "Function System.Collections.IEnumerable.GetEnumerator() As System.Collections.IEnumerator" IL_0018: stloc.0 IL_0019: br.s IL_0030 IL_001b: ldloc.0 IL_001c: callvirt "Function System.Collections.IEnumerator.get_Current() As Object" IL_0021: call "Function System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(Object) As Object" IL_0026: call "Function System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(Object) As Object" IL_002b: call "Sub System.Console.WriteLine(Object)" IL_0030: ldloc.0 IL_0031: callvirt "Function System.Collections.IEnumerator.MoveNext() As Boolean" IL_0036: brtrue.s IL_001b IL_0038: leave.s IL_004e } finally { IL_003a: ldloc.0 IL_003b: isinst "System.IDisposable" IL_0040: brfalse.s IL_004d IL_0042: ldloc.0 IL_0043: isinst "System.IDisposable" IL_0048: callvirt "Sub System.IDisposable.Dispose()" IL_004d: endfinally } IL_004e: ret } ]]>) End Sub <Fact> Public Sub TestForEachMutableStructEnumerablePattern() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Infer On Class C Public Shared Sub Main() Dim e As New Enumerable() System.Console.WriteLine(e.i) For Each x In e Next System.Console.WriteLine(e.i) End Sub End Class Structure Enumerable Public i As Integer Public Function GetEnumerator() As Enumerator i = i + 1 Return New Enumerator() End Function End Structure Structure Enumerator Private x As Integer Public ReadOnly Property Current() As Integer Get Return x End Get End Property Public Function MoveNext() As Boolean Return System.Threading.Interlocked.Increment(x) < 4 End Function End Structure </file> </compilation>, expectedOutput:=<![CDATA[ 0 1 ]]>).VerifyIL("C.Main", <![CDATA[ { // Code size 58 (0x3a) .maxstack 1 .locals init (Enumerable V_0, //e Enumerator V_1) IL_0000: ldloca.s V_0 IL_0002: initobj "Enumerable" IL_0008: ldloc.0 IL_0009: ldfld "Enumerable.i As Integer" IL_000e: call "Sub System.Console.WriteLine(Integer)" IL_0013: ldloca.s V_0 IL_0015: call "Function Enumerable.GetEnumerator() As Enumerator" IL_001a: stloc.1 IL_001b: br.s IL_0025 IL_001d: ldloca.s V_1 IL_001f: call "Function Enumerator.get_Current() As Integer" IL_0024: pop IL_0025: ldloca.s V_1 IL_0027: call "Function Enumerator.MoveNext() As Boolean" IL_002c: brtrue.s IL_001d IL_002e: ldloc.0 IL_002f: ldfld "Enumerable.i As Integer" IL_0034: call "Sub System.Console.WriteLine(Integer)" IL_0039: ret } ]]>) End Sub <WorkItem(542079, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542079")> <Fact> Public Sub TestForEachMutableStructEnumerableInterface() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Infer On Imports System.Collections Class C Public Shared Sub Main() Dim e As New Enumerable() System.Console.WriteLine(e.i) For Each x In e Next System.Console.WriteLine(e.i) End Sub End Class Structure Enumerable Implements IEnumerable Public i As Integer Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator i = i + 1 Return New Enumerator() End Function End Structure Structure Enumerator Implements IEnumerator Private x As Integer Public ReadOnly Property Current() As Object Implements IEnumerator.Current Get Return x End Get End Property Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext Return System.Threading.Interlocked.Increment(x) < 4 End Function Public Sub Reset() Implements IEnumerator.Reset x = 0 End Sub End Structure </file> </compilation>, expectedOutput:=<![CDATA[ 0 0 ]]>).VerifyIL("C.Main", <![CDATA[ { // Code size 92 (0x5c) .maxstack 1 .locals init (Enumerable V_0, //e System.Collections.IEnumerator V_1) IL_0000: ldloca.s V_0 IL_0002: initobj "Enumerable" IL_0008: ldloc.0 IL_0009: ldfld "Enumerable.i As Integer" IL_000e: call "Sub System.Console.WriteLine(Integer)" .try { IL_0013: ldloc.0 IL_0014: box "Enumerable" IL_0019: castclass "System.Collections.IEnumerable" IL_001e: callvirt "Function System.Collections.IEnumerable.GetEnumerator() As System.Collections.IEnumerator" IL_0023: stloc.1 IL_0024: br.s IL_0032 IL_0026: ldloc.1 IL_0027: callvirt "Function System.Collections.IEnumerator.get_Current() As Object" IL_002c: call "Function System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(Object) As Object" IL_0031: pop IL_0032: ldloc.1 IL_0033: callvirt "Function System.Collections.IEnumerator.MoveNext() As Boolean" IL_0038: brtrue.s IL_0026 IL_003a: leave.s IL_0050 } finally { IL_003c: ldloc.1 IL_003d: isinst "System.IDisposable" IL_0042: brfalse.s IL_004f IL_0044: ldloc.1 IL_0045: isinst "System.IDisposable" IL_004a: callvirt "Sub System.IDisposable.Dispose()" IL_004f: endfinally } IL_0050: ldloc.0 IL_0051: ldfld "Enumerable.i As Integer" IL_0056: call "Sub System.Console.WriteLine(Integer)" IL_005b: ret } ]]>) End Sub <Fact()> Public Sub TypeParameterAsEnumeratorTypeCanBeReferenceType() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Strict On Imports System Imports System.Collections Public Class Custom(Of S As {IEnumerator, IDisposable}) Public Function GetEnumerator() As S Return Nothing End Function End Class Class C1(Of S As {IEnumerator, IDisposable}) Public Sub DoStuff() Dim myCustomCollection As Custom(Of S) = nothing For Each element In myCustomCollection Console.WriteLine("goo") Next End Sub End Class Class C2 Public Shared Sub Main() End Sub End Class </file> </compilation>, options:=TestOptions.ReleaseExe).VerifyIL("C1(Of S).DoStuff", <![CDATA[ { // Code size 80 (0x50) .maxstack 1 .locals init (Custom(Of S) V_0, //myCustomCollection S V_1) IL_0000: ldnull IL_0001: stloc.0 .try { IL_0002: ldloc.0 IL_0003: callvirt "Function Custom(Of S).GetEnumerator() As S" IL_0008: stloc.1 IL_0009: br.s IL_0028 IL_000b: ldloca.s V_1 IL_000d: constrained. "S" IL_0013: callvirt "Function System.Collections.IEnumerator.get_Current() As Object" IL_0018: call "Function System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(Object) As Object" IL_001d: pop IL_001e: ldstr "goo" IL_0023: call "Sub System.Console.WriteLine(String)" IL_0028: ldloca.s V_1 IL_002a: constrained. "S" IL_0030: callvirt "Function System.Collections.IEnumerator.MoveNext() As Boolean" IL_0035: brtrue.s IL_000b IL_0037: leave.s IL_004f } finally { IL_0039: ldloc.1 IL_003a: box "S" IL_003f: brfalse.s IL_004e IL_0041: ldloca.s V_1 IL_0043: constrained. "S" IL_0049: callvirt "Sub System.IDisposable.Dispose()" IL_004e: endfinally } IL_004f: ret } ]]>) End Sub <Fact()> Public Sub TypeParameterAsEnumeratorTypeHasValueConstraint() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Strict On Imports System Imports System.Collections Public Class Custom(Of S As {IEnumerator, IDisposable, Structure}) Public Function GetEnumerator() As S Return Nothing End Function End Class Class C1(Of S As {IEnumerator, IDisposable, Structure}) Public Sub DoStuff() Dim myCustomCollection As Custom(Of S) = nothing For Each element In myCustomCollection Console.WriteLine("goo") Next End Sub End Class Class C2 Public Shared Sub Main() End Sub End Class </file> </compilation>, options:=TestOptions.ReleaseExe).VerifyIL("C1(Of S).DoStuff", <![CDATA[ { // Code size 72 (0x48) .maxstack 1 .locals init (Custom(Of S) V_0, //myCustomCollection S V_1) IL_0000: ldnull IL_0001: stloc.0 .try { IL_0002: ldloc.0 IL_0003: callvirt "Function Custom(Of S).GetEnumerator() As S" IL_0008: stloc.1 IL_0009: br.s IL_0028 IL_000b: ldloca.s V_1 IL_000d: constrained. "S" IL_0013: callvirt "Function System.Collections.IEnumerator.get_Current() As Object" IL_0018: call "Function System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(Object) As Object" IL_001d: pop IL_001e: ldstr "goo" IL_0023: call "Sub System.Console.WriteLine(String)" IL_0028: ldloca.s V_1 IL_002a: constrained. "S" IL_0030: callvirt "Function System.Collections.IEnumerator.MoveNext() As Boolean" IL_0035: brtrue.s IL_000b IL_0037: leave.s IL_0047 } finally { IL_0039: ldloca.s V_1 IL_003b: constrained. "S" IL_0041: callvirt "Sub System.IDisposable.Dispose()" IL_0046: endfinally } IL_0047: ret } ]]>) End Sub <Fact> Public Sub NoObjectCopyForGetCurrent() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Infer On Imports System Imports System.Collections.Generic Class C2 Public Structure S1 Public Field as Integer Public Sub New(x as integer) Field = x End Sub End Structure Public Shared Sub Main() dim coll = New List(Of S1) coll.add(new S1(23)) coll.add(new S1(42)) DoStuff(coll) End Sub Public Shared Sub DoStuff(coll as System.Collections.IEnumerable) for each x as Object in coll Console.WriteLine(Directcast(x,S1).Field) next End Sub End Class </file> </compilation>, expectedOutput:=<![CDATA[ 23 42 ]]>).VerifyIL("C2.DoStuff", <![CDATA[ { // Code size 66 (0x42) .maxstack 1 .locals init (System.Collections.IEnumerator V_0) .try { IL_0000: ldarg.0 IL_0001: callvirt "Function System.Collections.IEnumerable.GetEnumerator() As System.Collections.IEnumerator" IL_0006: stloc.0 IL_0007: br.s IL_0023 IL_0009: ldloc.0 IL_000a: callvirt "Function System.Collections.IEnumerator.get_Current() As Object" IL_000f: call "Function System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(Object) As Object" IL_0014: unbox "C2.S1" IL_0019: ldfld "C2.S1.Field As Integer" IL_001e: call "Sub System.Console.WriteLine(Integer)" IL_0023: ldloc.0 IL_0024: callvirt "Function System.Collections.IEnumerator.MoveNext() As Boolean" IL_0029: brtrue.s IL_0009 IL_002b: leave.s IL_0041 } finally { IL_002d: ldloc.0 IL_002e: isinst "System.IDisposable" IL_0033: brfalse.s IL_0040 IL_0035: ldloc.0 IL_0036: isinst "System.IDisposable" IL_003b: callvirt "Sub System.IDisposable.Dispose()" IL_0040: endfinally } IL_0041: ret } ]]>) ' there should be a check for null before calling Dispose End Sub <WorkItem(542185, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542185")> <Fact> Public Sub CustomDefinedType() Dim TEMP = CompileAndVerify( <compilation> <file name="a.vb"> Option Infer On Imports System.Collections.Generic Class C Public Shared Sub Main() Dim x = New B() End Sub End Class Class A Public Function GetEnumerator() As List(Of String).Enumerator Dim s = New List(Of String)() s.Add("A") s.Add("B") s.Add("C") Return s.GetEnumerator() End Function End Class Class B Inherits A Public Overloads Function GetEnumerator(ParamArray x As Integer()) As List(Of Integer).Enumerator Return New List(Of Integer).Enumerator() End Function End Class </file> </compilation>) End Sub <Fact> Public Sub ForEachQuery() CompileAndVerify( <compilation> <file name="a.vb"> Imports System.Linq Module Program Sub Main(args As String()) Dim ii As Integer() = New Integer() {1, 2, 3} For Each iii In ii.Where(Function(jj) jj >= ii(0)).Select(Function(jj) jj) System.Console.Write(iii) Next End Sub End Module </file> </compilation>, references:={LinqAssemblyRef}, expectedOutput:="123") End Sub <WorkItem(544311, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544311")> <Fact()> Public Sub ForEachWithMultipleDimArray() CompileAndVerify( <compilation> <file name="a.vb"> Option Strict On Imports System Module Program Sub Main() Dim k(,) = {{1}, {1}} For Each [Custom] In k Console.Write(VerifyStaticType([Custom], GetType(Integer))) Console.Write(VerifyStaticType([Custom], GetType(Object))) Exit For Next End Sub Function VerifyStaticType(Of T)(ByVal x As T, ByVal y As System.Type) As Boolean Return GetType(T) Is y End Function End Module </file> </compilation>, expectedOutput:="TrueFalse") End Sub <WorkItem(545519, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545519")> <Fact()> Public Sub NewForEachScopeDev11() Dim source = <compilation> <file name="a.vb"> imports system imports system.collections.generic Module m1 Sub Main() Dim actions = New List(Of Action)() Dim values = New List(Of Integer) From {1, 2, 3} ' test lifting of control variable in loop body when collection is array For Each i As Integer In values actions.Add(Sub() Console.WriteLine(i)) Next For Each a In actions a() Next End Sub End Module </file> </compilation> CompileAndVerify(source, expectedOutput:=<![CDATA[ 1 2 3 ]]>).VerifyIL("m1.Main", <![CDATA[ { // Code size 154 (0x9a) .maxstack 3 .locals init (System.Collections.Generic.List(Of System.Action) V_0, //actions System.Collections.Generic.List(Of Integer) V_1, //values System.Collections.Generic.List(Of Integer).Enumerator V_2, m1._Closure$__0-0 V_3, //$VB$Closure_0 System.Collections.Generic.List(Of System.Action).Enumerator V_4) IL_0000: newobj "Sub System.Collections.Generic.List(Of System.Action)..ctor()" IL_0005: stloc.0 IL_0006: newobj "Sub System.Collections.Generic.List(Of Integer)..ctor()" IL_000b: dup IL_000c: ldc.i4.1 IL_000d: callvirt "Sub System.Collections.Generic.List(Of Integer).Add(Integer)" IL_0012: dup IL_0013: ldc.i4.2 IL_0014: callvirt "Sub System.Collections.Generic.List(Of Integer).Add(Integer)" IL_0019: dup IL_001a: ldc.i4.3 IL_001b: callvirt "Sub System.Collections.Generic.List(Of Integer).Add(Integer)" IL_0020: stloc.1 .try { IL_0021: ldloc.1 IL_0022: callvirt "Function System.Collections.Generic.List(Of Integer).GetEnumerator() As System.Collections.Generic.List(Of Integer).Enumerator" IL_0027: stloc.2 IL_0028: br.s IL_0050 IL_002a: ldloc.3 IL_002b: newobj "Sub m1._Closure$__0-0..ctor(m1._Closure$__0-0)" IL_0030: stloc.3 IL_0031: ldloc.3 IL_0032: ldloca.s V_2 IL_0034: call "Function System.Collections.Generic.List(Of Integer).Enumerator.get_Current() As Integer" IL_0039: stfld "m1._Closure$__0-0.$VB$Local_i As Integer" IL_003e: ldloc.0 IL_003f: ldloc.3 IL_0040: ldftn "Sub m1._Closure$__0-0._Lambda$__0()" IL_0046: newobj "Sub System.Action..ctor(Object, System.IntPtr)" IL_004b: callvirt "Sub System.Collections.Generic.List(Of System.Action).Add(System.Action)" IL_0050: ldloca.s V_2 IL_0052: call "Function System.Collections.Generic.List(Of Integer).Enumerator.MoveNext() As Boolean" IL_0057: brtrue.s IL_002a IL_0059: leave.s IL_0069 } finally { IL_005b: ldloca.s V_2 IL_005d: constrained. "System.Collections.Generic.List(Of Integer).Enumerator" IL_0063: callvirt "Sub System.IDisposable.Dispose()" IL_0068: endfinally } IL_0069: nop .try { IL_006a: ldloc.0 IL_006b: callvirt "Function System.Collections.Generic.List(Of System.Action).GetEnumerator() As System.Collections.Generic.List(Of System.Action).Enumerator" IL_0070: stloc.s V_4 IL_0072: br.s IL_0080 IL_0074: ldloca.s V_4 IL_0076: call "Function System.Collections.Generic.List(Of System.Action).Enumerator.get_Current() As System.Action" IL_007b: callvirt "Sub System.Action.Invoke()" IL_0080: ldloca.s V_4 IL_0082: call "Function System.Collections.Generic.List(Of System.Action).Enumerator.MoveNext() As Boolean" IL_0087: brtrue.s IL_0074 IL_0089: leave.s IL_0099 } finally { IL_008b: ldloca.s V_4 IL_008d: constrained. "System.Collections.Generic.List(Of System.Action).Enumerator" IL_0093: callvirt "Sub System.IDisposable.Dispose()" IL_0098: endfinally } IL_0099: ret } ]]>) End Sub <WorkItem(545519, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545519")> <Fact()> Public Sub NewForEachScopeDev11_2() Dim source = <compilation> <file name="a.vb"> imports system imports system.collections.generic Module m1 Sub Main() ' Test Array Dim x(10) as action ' test lifting of control variable in loop body and lifting of control variable when used ' in the collection expression itself. For Each i As Integer In (function() {i + 1, i + 2, i + 3})() x(i) = Sub() console.writeline(i.toString) Next for i = 1 to 3 x(i).invoke() next End Sub End Module </file> </compilation> CompileAndVerify(source, expectedOutput:=<![CDATA[ 1 2 3 ]]>).VerifyIL("m1.Main", <![CDATA[ { // Code size 93 (0x5d) .maxstack 4 .locals init (System.Action() V_0, //x Integer() V_1, Integer V_2, m1._Closure$__0-1 V_3, //$VB$Closure_0 Integer V_4) //i IL_0000: ldc.i4.s 11 IL_0002: newarr "System.Action" IL_0007: stloc.0 IL_0008: newobj "Sub m1._Closure$__0-0..ctor()" IL_000d: callvirt "Function m1._Closure$__0-0._Lambda$__0() As Integer()" IL_0012: stloc.1 IL_0013: ldc.i4.0 IL_0014: stloc.2 IL_0015: br.s IL_003f IL_0017: ldloc.3 IL_0018: newobj "Sub m1._Closure$__0-1..ctor(m1._Closure$__0-1)" IL_001d: stloc.3 IL_001e: ldloc.3 IL_001f: ldloc.1 IL_0020: ldloc.2 IL_0021: ldelem.i4 IL_0022: stfld "m1._Closure$__0-1.$VB$Local_i As Integer" IL_0027: ldloc.0 IL_0028: ldloc.3 IL_0029: ldfld "m1._Closure$__0-1.$VB$Local_i As Integer" IL_002e: ldloc.3 IL_002f: ldftn "Sub m1._Closure$__0-1._Lambda$__1()" IL_0035: newobj "Sub System.Action..ctor(Object, System.IntPtr)" IL_003a: stelem.ref IL_003b: ldloc.2 IL_003c: ldc.i4.1 IL_003d: add.ovf IL_003e: stloc.2 IL_003f: ldloc.2 IL_0040: ldloc.1 IL_0041: ldlen IL_0042: conv.i4 IL_0043: blt.s IL_0017 IL_0045: ldc.i4.1 IL_0046: stloc.s V_4 IL_0048: ldloc.0 IL_0049: ldloc.s V_4 IL_004b: ldelem.ref IL_004c: callvirt "Sub System.Action.Invoke()" IL_0051: ldloc.s V_4 IL_0053: ldc.i4.1 IL_0054: add.ovf IL_0055: stloc.s V_4 IL_0057: ldloc.s V_4 IL_0059: ldc.i4.3 IL_005a: ble.s IL_0048 IL_005c: ret } ]]>) End Sub <WorkItem(545519, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545519")> <Fact()> Public Sub NewForEachScopeDev11_3() Dim source = <compilation> <file name="a.vb"> imports system imports system.collections.generic Module m1 Sub Main() ' Test Array Dim x(10) as action for j = 0 to 2 ' test lifting of control variable in loop body and lifting of control variable when used ' in the collection expression itself. for each i as integer in (function(a) goo())(i) x(i) = sub() console.write(i.toString & " ") next for i = 1 to 3 x(i).invoke() next Console.Writeline() next j End Sub function goo() as IEnumerable(of Integer) return new list(of integer) from {1, 2, 3} end function End Module </file> </compilation> CompileAndVerify(source, expectedOutput:=<![CDATA[1 2 3 1 2 3 1 2 3 ]]>).VerifyIL("m1.Main", <![CDATA[ { // Code size 170 (0xaa) .maxstack 4 .locals init (System.Action() V_0, //x Integer V_1, //j Integer V_2, System.Collections.Generic.IEnumerator(Of Integer) V_3, m1._Closure$__0-0 V_4, //$VB$Closure_0 Integer V_5) //i IL_0000: ldc.i4.s 11 IL_0002: newarr "System.Action" IL_0007: stloc.0 IL_0008: ldc.i4.0 IL_0009: stloc.1 IL_000a: nop .try { IL_000b: ldsfld "m1._Closure$__.$I0-0 As <generated method>" IL_0010: brfalse.s IL_0019 IL_0012: ldsfld "m1._Closure$__.$I0-0 As <generated method>" IL_0017: br.s IL_002f IL_0019: ldsfld "m1._Closure$__.$I As m1._Closure$__" IL_001e: ldftn "Function m1._Closure$__._Lambda$__0-0(Object) As System.Collections.Generic.IEnumerable(Of Integer)" IL_0024: newobj "Sub VB$AnonymousDelegate_0(Of Object, System.Collections.Generic.IEnumerable(Of Integer))..ctor(Object, System.IntPtr)" IL_0029: dup IL_002a: stsfld "m1._Closure$__.$I0-0 As <generated method>" IL_002f: ldloc.2 IL_0030: box "Integer" IL_0035: callvirt "Function VB$AnonymousDelegate_0(Of Object, System.Collections.Generic.IEnumerable(Of Integer)).Invoke(Object) As System.Collections.Generic.IEnumerable(Of Integer)" IL_003a: callvirt "Function System.Collections.Generic.IEnumerable(Of Integer).GetEnumerator() As System.Collections.Generic.IEnumerator(Of Integer)" IL_003f: stloc.3 IL_0040: br.s IL_006e IL_0042: ldloc.s V_4 IL_0044: newobj "Sub m1._Closure$__0-0..ctor(m1._Closure$__0-0)" IL_0049: stloc.s V_4 IL_004b: ldloc.s V_4 IL_004d: ldloc.3 IL_004e: callvirt "Function System.Collections.Generic.IEnumerator(Of Integer).get_Current() As Integer" IL_0053: stfld "m1._Closure$__0-0.$VB$Local_i As Integer" IL_0058: ldloc.0 IL_0059: ldloc.s V_4 IL_005b: ldfld "m1._Closure$__0-0.$VB$Local_i As Integer" IL_0060: ldloc.s V_4 IL_0062: ldftn "Sub m1._Closure$__0-0._Lambda$__1()" IL_0068: newobj "Sub System.Action..ctor(Object, System.IntPtr)" IL_006d: stelem.ref IL_006e: ldloc.3 IL_006f: callvirt "Function System.Collections.IEnumerator.MoveNext() As Boolean" IL_0074: brtrue.s IL_0042 IL_0076: leave.s IL_0082 } finally { IL_0078: ldloc.3 IL_0079: brfalse.s IL_0081 IL_007b: ldloc.3 IL_007c: callvirt "Sub System.IDisposable.Dispose()" IL_0081: endfinally } IL_0082: ldc.i4.1 IL_0083: stloc.s V_5 IL_0085: ldloc.0 IL_0086: ldloc.s V_5 IL_0088: ldelem.ref IL_0089: callvirt "Sub System.Action.Invoke()" IL_008e: ldloc.s V_5 IL_0090: ldc.i4.1 IL_0091: add.ovf IL_0092: stloc.s V_5 IL_0094: ldloc.s V_5 IL_0096: ldc.i4.3 IL_0097: ble.s IL_0085 IL_0099: call "Sub System.Console.WriteLine()" IL_009e: ldloc.1 IL_009f: ldc.i4.1 IL_00a0: add.ovf IL_00a1: stloc.1 IL_00a2: ldloc.1 IL_00a3: ldc.i4.2 IL_00a4: ble IL_000a IL_00a9: ret } ]]>) End Sub <WorkItem(545519, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545519")> <Fact()> Public Sub NewForEachScopeDev11_4() Dim source = <compilation> <file name="a.vb"> imports system imports system.collections.generic Module m1 Sub Main() ' Test Array Dim lambdas As New List(Of Action) 'Expected 0,1,2, 0,1,2, 0,1,2 lambdas.clear For y = 1 To 3 ' test lifting of control variable in loop body and lifting of control variable when used ' in the collection expression itself. The for each itself is nested in a for loop. For Each x as integer In (function(a) x = x + 1 return {a, x, 2} end function)(x) lambdas.add( Sub() Console.Write(x.ToString + "," ) ) Next lambdas.add(sub() Console.WriteLine()) Next For Each lambda In lambdas lambda() Next End Sub End Module </file> </compilation> CompileAndVerify(source, expectedOutput:=<![CDATA[ 0,1,2, 0,1,2, 0,1,2, ]]>).VerifyIL("m1.Main", <![CDATA[ { // Code size 195 (0xc3) .maxstack 3 .locals init (System.Collections.Generic.List(Of System.Action) V_0, //lambdas Integer V_1, //y Object() V_2, Integer V_3, m1._Closure$__0-1 V_4, //$VB$Closure_0 System.Collections.Generic.List(Of System.Action).Enumerator V_5) IL_0000: newobj "Sub System.Collections.Generic.List(Of System.Action)..ctor()" IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: callvirt "Sub System.Collections.Generic.List(Of System.Action).Clear()" IL_000c: ldc.i4.1 IL_000d: stloc.1 IL_000e: newobj "Sub m1._Closure$__0-0..ctor()" IL_0013: dup IL_0014: ldfld "m1._Closure$__0-0.$VB$NonLocal_2 As Integer" IL_0019: box "Integer" IL_001e: callvirt "Function m1._Closure$__0-0._Lambda$__0(Object) As Object()" IL_0023: stloc.2 IL_0024: ldc.i4.0 IL_0025: stloc.3 IL_0026: br.s IL_0057 IL_0028: ldloc.s V_4 IL_002a: newobj "Sub m1._Closure$__0-1..ctor(m1._Closure$__0-1)" IL_002f: stloc.s V_4 IL_0031: ldloc.s V_4 IL_0033: ldloc.2 IL_0034: ldloc.3 IL_0035: ldelem.ref IL_0036: call "Function Microsoft.VisualBasic.CompilerServices.Conversions.ToInteger(Object) As Integer" IL_003b: stfld "m1._Closure$__0-1.$VB$Local_x As Integer" IL_0040: ldloc.0 IL_0041: ldloc.s V_4 IL_0043: ldftn "Sub m1._Closure$__0-1._Lambda$__1()" IL_0049: newobj "Sub System.Action..ctor(Object, System.IntPtr)" IL_004e: callvirt "Sub System.Collections.Generic.List(Of System.Action).Add(System.Action)" IL_0053: ldloc.3 IL_0054: ldc.i4.1 IL_0055: add.ovf IL_0056: stloc.3 IL_0057: ldloc.3 IL_0058: ldloc.2 IL_0059: ldlen IL_005a: conv.i4 IL_005b: blt.s IL_0028 IL_005d: ldloc.0 IL_005e: ldsfld "m1._Closure$__.$I0-2 As System.Action" IL_0063: brfalse.s IL_006c IL_0065: ldsfld "m1._Closure$__.$I0-2 As System.Action" IL_006a: br.s IL_0082 IL_006c: ldsfld "m1._Closure$__.$I As m1._Closure$__" IL_0071: ldftn "Sub m1._Closure$__._Lambda$__0-2()" IL_0077: newobj "Sub System.Action..ctor(Object, System.IntPtr)" IL_007c: dup IL_007d: stsfld "m1._Closure$__.$I0-2 As System.Action" IL_0082: callvirt "Sub System.Collections.Generic.List(Of System.Action).Add(System.Action)" IL_0087: ldloc.1 IL_0088: ldc.i4.1 IL_0089: add.ovf IL_008a: stloc.1 IL_008b: ldloc.1 IL_008c: ldc.i4.3 IL_008d: ble IL_000e IL_0092: nop .try { IL_0093: ldloc.0 IL_0094: callvirt "Function System.Collections.Generic.List(Of System.Action).GetEnumerator() As System.Collections.Generic.List(Of System.Action).Enumerator" IL_0099: stloc.s V_5 IL_009b: br.s IL_00a9 IL_009d: ldloca.s V_5 IL_009f: call "Function System.Collections.Generic.List(Of System.Action).Enumerator.get_Current() As System.Action" IL_00a4: callvirt "Sub System.Action.Invoke()" IL_00a9: ldloca.s V_5 IL_00ab: call "Function System.Collections.Generic.List(Of System.Action).Enumerator.MoveNext() As Boolean" IL_00b0: brtrue.s IL_009d IL_00b2: leave.s IL_00c2 } finally { IL_00b4: ldloca.s V_5 IL_00b6: constrained. "System.Collections.Generic.List(Of System.Action).Enumerator" IL_00bc: callvirt "Sub System.IDisposable.Dispose()" IL_00c1: endfinally } IL_00c2: ret } ]]>) End Sub <Fact> Public Sub ForEachLateBinding() Dim compilation1 = CompileAndVerify( <compilation> <file name="a.vb"> Option Strict Off imports system Class C Shared Sub Main() Dim o As Object = {1, 2, 3} For Each x In o console.writeline(x) Next End Sub End Class </file> </compilation>, options:=TestOptions.ReleaseExe.WithModuleName("MODULE"), expectedOutput:=<![CDATA[ 1 2 3 ]]>).VerifyIL("C.Main", <![CDATA[ { // Code size 84 (0x54) .maxstack 3 .locals init (Object V_0, //o System.Collections.IEnumerator V_1) IL_0000: ldc.i4.3 IL_0001: newarr "Integer" IL_0006: dup IL_0007: ldtoken "<PrivateImplementationDetails>.__StaticArrayInitTypeSize=12 <PrivateImplementationDetails>.4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D" IL_000c: call "Sub System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)" IL_0011: stloc.0 .try { IL_0012: ldloc.0 IL_0013: castclass "System.Collections.IEnumerable" IL_0018: callvirt "Function System.Collections.IEnumerable.GetEnumerator() As System.Collections.IEnumerator" IL_001d: stloc.1 IL_001e: br.s IL_0035 IL_0020: ldloc.1 IL_0021: callvirt "Function System.Collections.IEnumerator.get_Current() As Object" IL_0026: call "Function System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(Object) As Object" IL_002b: call "Function System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(Object) As Object" IL_0030: call "Sub System.Console.WriteLine(Object)" IL_0035: ldloc.1 IL_0036: callvirt "Function System.Collections.IEnumerator.MoveNext() As Boolean" IL_003b: brtrue.s IL_0020 IL_003d: leave.s IL_0053 } finally { IL_003f: ldloc.1 IL_0040: isinst "System.IDisposable" IL_0045: brfalse.s IL_0052 IL_0047: ldloc.1 IL_0048: isinst "System.IDisposable" IL_004d: callvirt "Sub System.IDisposable.Dispose()" IL_0052: endfinally } IL_0053: ret } ]]>).Compilation End Sub End Class End Namespace