diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs index 8d24b8c885bee..f65d6bd219ef1 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs @@ -747,12 +747,12 @@ private static void RemoveLessDerivedMembers(ArrayBuilder - Protected HasFinalizerState As Boolean = True + Private _hasFinalizerState As Boolean = True ''' ''' If hasFinalizerState is true, this is the state for finalization from anywhere in this try block. ''' Initially set to -1, representing the no-op finalization required at the top level. ''' - Protected CurrentFinalizerState As Integer = -1 + Private _currentFinalizerState As Integer = -1 ''' ''' The set of local variables and parameters that were hoisted and need a proxy. ''' - Protected Friend ReadOnly HoistedVariables As IReadOnlySet(Of Symbol) = Nothing + Private ReadOnly _hoistedVariables As IReadOnlySet(Of Symbol) = Nothing Private ReadOnly _synthesizedLocalOrdinals As SynthesizedLocalOrdinalsDispenser Private _nextFreeHoistedLocalSlot As Integer @@ -84,7 +84,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Me.F = F Me.StateField = stateField Me.CachedState = F.SynthesizedLocal(F.SpecialType(SpecialType.System_Int32), SynthesizedLocalKind.StateMachineCachedState, F.Syntax) - Me.HoistedVariables = hoistedVariables + Me._hoistedVariables = hoistedVariables Me._synthesizedLocalOrdinals = synthesizedLocalOrdinals Me._nextFreeHoistedLocalSlot = nextFreeHoistedLocalSlot @@ -148,15 +148,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Me.Dispatches = New Dictionary(Of LabelSymbol, List(Of Integer))() End If - If Not Me.HasFinalizerState Then - Me.CurrentFinalizerState = Me.NextState + If Not Me._hasFinalizerState Then + Me._currentFinalizerState = Me.NextState Me.NextState += 1 - Me.HasFinalizerState = True + Me._hasFinalizerState = True End If Dim resumeLabel As GeneratedLabelSymbol = Me.F.GenerateLabel(ResumeLabelName) Me.Dispatches.Add(resumeLabel, New List(Of Integer)() From {stateNumber}) - Me.FinalizerStateMap.Add(stateNumber, Me.CurrentFinalizerState) + Me.FinalizerStateMap.Add(stateNumber, Me._currentFinalizerState) Return New StateInfo(stateNumber, resumeLabel) End Function @@ -232,7 +232,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Private Function NeedsProxy(localOrParameter As Symbol) As Boolean Debug.Assert(localOrParameter.Kind = SymbolKind.Local OrElse localOrParameter.Kind = SymbolKind.Parameter) - Return HoistedVariables.Contains(localOrParameter) + Return _hoistedVariables.Contains(localOrParameter) End Function Friend MustOverride Sub AddProxyFieldsForStateMachineScope(proxy As TProxy, proxyFields As ArrayBuilder(Of FieldSymbol)) @@ -254,22 +254,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Public Overrides Function VisitTryStatement(node As BoundTryStatement) As BoundNode Dim oldDispatches As Dictionary(Of LabelSymbol, List(Of Integer)) = Me.Dispatches - Dim oldFinalizerState As Integer = Me.CurrentFinalizerState - Dim oldHasFinalizerState As Boolean = Me.HasFinalizerState + Dim oldFinalizerState As Integer = Me._currentFinalizerState + Dim oldHasFinalizerState As Boolean = Me._hasFinalizerState Me.Dispatches = Nothing - Me.CurrentFinalizerState = -1 - Me.HasFinalizerState = False + Me._currentFinalizerState = -1 + Me._hasFinalizerState = False Dim tryBlock As BoundBlock = Me.F.Block(DirectCast(Me.Visit(node.TryBlock), BoundStatement)) Dim dispatchLabel As GeneratedLabelSymbol = Nothing If Me.Dispatches IsNot Nothing Then dispatchLabel = Me.F.GenerateLabel("tryDispatch") - If Me.HasFinalizerState Then + If Me._hasFinalizerState Then ' cause the current finalizer state to arrive here and then "return false" Dim finalizer As GeneratedLabelSymbol = Me.F.GenerateLabel("finalizer") - Me.Dispatches.Add(finalizer, New List(Of Integer)() From {Me.CurrentFinalizerState}) + Me.Dispatches.Add(finalizer, New List(Of Integer)() From {Me._currentFinalizerState}) Dim skipFinalizer As GeneratedLabelSymbol = Me.F.GenerateLabel("skipFinalizer") tryBlock = Me.F.Block(Me.F.HiddenSequencePoint(), @@ -293,8 +293,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic oldDispatches.Add(dispatchLabel, New List(Of Integer)(From kv In Dispatches.Values From n In kv Order By n Select n)) End If - Me.HasFinalizerState = oldHasFinalizerState - Me.CurrentFinalizerState = oldFinalizerState + Me._hasFinalizerState = oldHasFinalizerState + Me._currentFinalizerState = oldFinalizerState Me.Dispatches = oldDispatches @@ -329,28 +329,39 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return Me.MaterializeProxy(node, Me.Proxies(Me.TopLevelMethod.MeParameter)) End Function - Public Overrides Function VisitCatchBlock(node As BoundCatchBlock) As BoundNode - ' Neither Async nor Iterator function allows await/yield in Catch block, - ' thus, it should not capture/hoist catch block local - Dim rewrittenCatchLocal As LocalSymbol = Nothing - - Dim origLocal As LocalSymbol = node.LocalOpt - If origLocal IsNot Nothing Then - ' local may be either the original local of a frame reference - Debug.Assert(Not Me.Proxies.ContainsKey(origLocal), "captured local should not need rewriting") + Private Function TryRewriteLocal(local As LocalSymbol) As LocalSymbol + If NeedsProxy(local) Then + ' no longer a local symbol + Return Nothing + End If - Dim newType = VisitType(origLocal.Type) - If newType = origLocal.Type Then + Dim newLocal As LocalSymbol = Nothing + If Not LocalMap.TryGetValue(local, newLocal) Then + Dim newType = VisitType(local.Type) + If newType = local.Type Then ' keeping same local - rewrittenCatchLocal = origLocal - + newLocal = local Else ' need a local of a different type - rewrittenCatchLocal = LocalSymbol.Create(origLocal, newType) - Me.LocalMap.Add(origLocal, rewrittenCatchLocal) + newLocal = LocalSymbol.Create(local, newType) + LocalMap.Add(local, newLocal) End If End If + Return newLocal + End Function + + Public Overrides Function VisitCatchBlock(node As BoundCatchBlock) As BoundNode + ' Yield/Await aren't supported in Catch block, but we need to + ' rewrite the type of the variable owned by the catch block. + ' Note that this variable might be a closure frame reference. + Dim rewrittenCatchLocal As LocalSymbol = Nothing + + Dim origLocal As LocalSymbol = node.LocalOpt + If origLocal IsNot Nothing Then + rewrittenCatchLocal = TryRewriteLocal(origLocal) + End If + Dim rewrittenExceptionVariable As BoundExpression = DirectCast(Me.Visit(node.ExceptionSourceOpt), BoundExpression) ' rewrite filter and body diff --git a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenAsyncTests.vb b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenAsyncTests.vb index f7a247ee1e451..127d31e6ff864 100644 --- a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenAsyncTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenAsyncTests.vb @@ -8300,6 +8300,80 @@ BC42356: This async method lacks 'Await' operators and so will run synchronously ]]>) End Using End Sub + + + + Public Sub CatchInIteratorStateMachine() + CompileAndVerify( + + +Imports System +Imports System.Collections +Class C + Shared Function F() As Object + Throw New ArgumentException() + End Function + Shared Iterator Function M() As IEnumerable + Dim o As Object + Try + o = F() + Catch e As Exception + o = e + End Try + Yield o + End Function + Shared Sub Main() + For Each o in M() + Console.WriteLine(o) + Next + End Sub +End Class + +, + options:=TestOptions.DebugExe, + useLatestFramework:=True, + expectedOutput:= +"System.ArgumentException: Value does not fall within the expected range. + at C.F() + at C.VB$StateMachine_2_M.MoveNext()") + End Sub + + + + Public Sub CatchInAsyncStateMachine() + CompileAndVerify( + + +Imports System +Imports System.Threading.Tasks +Class C + Shared Function F() As Object + Throw New ArgumentException() + End Function + Shared Async Function M() As Task(Of Object) + Dim o As Object + Try + o = F() + Catch e As Exception + o = e + End Try + Return o + End Function + Shared Sub Main() + Dim o = M().Result + Console.WriteLine(o) + End Sub +End Class + +, + options:=TestOptions.DebugExe, + useLatestFramework:=True, + expectedOutput:= +"System.ArgumentException: Value does not fall within the expected range. + at C.F() + at C.VB$StateMachine_2_M.MoveNext()") + End Sub + End Class End Namespace diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/LocalsTests.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/LocalsTests.cs index 5b3eae6c1983c..86bca7ac6acb0 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/LocalsTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/LocalsTests.cs @@ -2332,6 +2332,66 @@ .locals init (int V_0, locals.Free(); } + [WorkItem(1115030)] + [Fact(Skip = "1115030")] + public void CatchInAsyncStateMachine() + { + var source = +@"using System; +using System.Threading.Tasks; +class C +{ + static object F() + { + throw new ArgumentException(); + } + static async Task M() + { + object o; + try + { + o = F(); + } + catch (Exception e) + { +#line 999 + o = e; + } + } +}"; + var compilation0 = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugDll); + var runtime = CreateRuntimeInstance(compilation0); + var context = CreateMethodContext( + runtime, + methodName: "C.d__1.MoveNext", + atLineNumber: 999); + var testData = new CompilationTestData(); + var locals = ArrayBuilder.GetInstance(); + string typeName; + var assembly = context.CompileGetLocals(locals, argumentsOnly: false, typeName: out typeName, testData: testData); + VerifyLocal(testData, typeName, locals[0], "<>m0", "o", expectedILOpt: +@"{ + // Code size 7 (0x7) + .maxstack 1 + .locals init (int V_0, + System.Exception V_1) + IL_0000: ldarg.0 + IL_0001: ldfld ""object C.d__1.5__1"" + IL_0006: ret +}"); + VerifyLocal(testData, typeName, locals[1], "<>m1", "e", expectedILOpt: +@"{ + // Code size 7 (0x7) + .maxstack 1 + .locals init (int V_0, + System.Exception V_1) + IL_0000: ldarg.0 + IL_0001: ldfld ""System.Exception C.d__1.5__2"" + IL_0006: ret +}"); + locals.Free(); + } + private static void GetLocals(RuntimeInstance runtime, string methodName, bool argumentsOnly, ArrayBuilder locals, int count, out string typeName, out CompilationTestData testData) { var context = CreateMethodContext(runtime, methodName); diff --git a/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/LocalsTests.vb b/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/LocalsTests.vb index e1074a9a20544..295040285709b 100644 --- a/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/LocalsTests.vb +++ b/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/LocalsTests.vb @@ -2355,6 +2355,65 @@ End Class ") End Sub + + + Public Sub CatchInAsyncStateMachine() + Const source = +"Imports System +Imports System.Threading.Tasks +Class C + Shared Function F() As Object + Throw New ArgumentException() + End Function + Shared Async Function M() As Task + Dim o As Object + Try + o = F() + Catch e As Exception +#ExternalSource(""test"", 999) + o = e +#End ExternalSource + End Try + End Function +End Class" + Dim comp = CreateCompilationWithReferences( + MakeSources(source), + {MscorlibRef_v4_0_30316_17626, MsvbRef_v4_0_30319_17929, SystemCoreRef_v4_0_30319_17929}, + TestOptions.DebugDll) + Dim runtime = CreateRuntimeInstance(comp) + Dim context = CreateMethodContext( + runtime, + methodName:="C.VB$StateMachine_2_M.MoveNext", + atLineNumber:=999) + Dim testData = New CompilationTestData() + Dim locals = ArrayBuilder(Of LocalAndMethod).GetInstance() + Dim typeName As String = Nothing + Dim assembly = context.CompileGetLocals(locals, argumentsOnly:=False, typeName:=typeName, testData:=testData) + VerifyLocal(testData, typeName, locals(0), "<>m0", "o", expectedILOpt:= +"{ + // Code size 7 (0x7) + .maxstack 1 + .locals init (Integer V_0, + System.Exception V_1, + System.Exception V_2) + IL_0000: ldarg.0 + IL_0001: ldfld ""C.VB$StateMachine_2_M.$VB$ResumableLocal_o$0 As Object"" + IL_0006: ret +}") + VerifyLocal(testData, typeName, locals(1), "<>m1", "e", expectedILOpt:= +"{ + // Code size 7 (0x7) + .maxstack 1 + .locals init (Integer V_0, + System.Exception V_1, + System.Exception V_2) + IL_0000: ldarg.0 + IL_0001: ldfld ""C.VB$StateMachine_2_M.$VB$ResumableLocal_e$1 As System.Exception"" + IL_0006: ret +}") + locals.Free() + End Sub + Private Shared Sub GetLocals(runtime As RuntimeInstance, methodName As String, argumentsOnly As Boolean, locals As ArrayBuilder(Of LocalAndMethod), count As Integer, ByRef typeName As String, ByRef testData As CompilationTestData) Dim context = CreateMethodContext(runtime, methodName) testData = New CompilationTestData() diff --git a/src/Interactive/HostTest/InteractiveHostTests.cs b/src/Interactive/HostTest/InteractiveHostTests.cs index d418896a1185f..c4075aea31450 100644 --- a/src/Interactive/HostTest/InteractiveHostTests.cs +++ b/src/Interactive/HostTest/InteractiveHostTests.cs @@ -737,7 +737,7 @@ public void AddReference_MutlipleReferencesWithSameWeakIdentity() ////"); //// initScript.WriteAllText(@" - ////using System.Console; + ////using static System.Console; ////using System.Linq.Expressions; ////WriteLine(Expression.Constant(123)); ////"); @@ -785,7 +785,7 @@ public void AddReference_MutlipleReferencesWithSameWeakIdentity() ////"); //// initScript.WriteAllText(@" - ////using System.Console; + ////using static System.Console; ////using System.Numerics; ////WriteLine(new Complex(12, 6).Real + C.Main()); ////"); diff --git a/src/InteractiveWindow/EditorTest/InteractiveWindowEditorsFactoryService.cs b/src/InteractiveWindow/EditorTest/InteractiveWindowEditorsFactoryService.cs index 1738322d857ad..5a6c22c88c8d0 100644 --- a/src/InteractiveWindow/EditorTest/InteractiveWindowEditorsFactoryService.cs +++ b/src/InteractiveWindow/EditorTest/InteractiveWindowEditorsFactoryService.cs @@ -4,9 +4,8 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Utilities; -using Microsoft.VisualStudio.InteractiveWindow; -namespace Roslyn.InteractiveWindow.UnitTests +namespace Microsoft.VisualStudio.InteractiveWindow.UnitTests { [Export(typeof(IInteractiveWindowEditorFactoryService))] internal class InteractiveWindowEditorsFactoryService : IInteractiveWindowEditorFactoryService