diff --git a/eng/Versions.props b/eng/Versions.props index 59017cb7ada3d..e9b51a29fbeee 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -93,8 +93,8 @@ 0.8.31-beta 1.0.35 1.4.0 - 1.1.0-beta2-21528-01 - 1.1.0-beta2-21528-01 + 1.1.0-beta2-22273-03 + 1.1.0-beta2-22273-03 17.0.0-beta1.21524.1 1.7.0-beta-21528-01 5.0.0 diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs index 505f9aebffbcf..7478bf5a2d924 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs @@ -264,6 +264,7 @@ private static MethodSymbol GetEntryPoint(CSharpCompilation compilation, PEModul VariableSlotAllocator lazyVariableSlotAllocator = null; var lambdaDebugInfoBuilder = ArrayBuilder.GetInstance(); var closureDebugInfoBuilder = ArrayBuilder.GetInstance(); + var stateMachineStateDebugInfoBuilder = ArrayBuilder.GetInstance(); StateMachineTypeSymbol stateMachineTypeOpt = null; const int methodOrdinal = -1; @@ -280,6 +281,7 @@ private static MethodSymbol GetEntryPoint(CSharpCompilation compilation, PEModul ref lazyVariableSlotAllocator, lambdaDebugInfoBuilder, closureDebugInfoBuilder, + stateMachineStateDebugInfoBuilder, out stateMachineTypeOpt); Debug.Assert((object)lazyVariableSlotAllocator == null); @@ -287,9 +289,11 @@ private static MethodSymbol GetEntryPoint(CSharpCompilation compilation, PEModul Debug.Assert(dynamicAnalysisSpans.IsEmpty); Debug.Assert(lambdaDebugInfoBuilder.IsEmpty()); Debug.Assert(closureDebugInfoBuilder.IsEmpty()); + Debug.Assert(stateMachineStateDebugInfoBuilder.IsEmpty()); lambdaDebugInfoBuilder.Free(); closureDebugInfoBuilder.Free(); + stateMachineStateDebugInfoBuilder.Free(); if (emitMethodBodies) { @@ -300,6 +304,7 @@ private static MethodSymbol GetEntryPoint(CSharpCompilation compilation, PEModul loweredBody, ImmutableArray.Empty, ImmutableArray.Empty, + ImmutableArray.Empty, stateMachineTypeOpt: null, variableSlotAllocatorOpt: null, diagnostics: diagnostics, @@ -698,6 +703,7 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState) return; } + var stateMachineStateDebugInfoBuilder = ArrayBuilder.GetInstance(); var oldImportChain = compilationState.CurrentImportChain; try { @@ -727,13 +733,13 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState) { // Local functions can be iterators as well as be async (lambdas can only be async), so we need to lower both iterators and async IteratorStateMachine iteratorStateMachine; - BoundStatement loweredBody = IteratorRewriter.Rewrite(methodWithBody.Body, method, methodOrdinal, variableSlotAllocatorOpt, compilationState, diagnosticsThisMethod, out iteratorStateMachine); + BoundStatement loweredBody = IteratorRewriter.Rewrite(methodWithBody.Body, method, methodOrdinal, stateMachineStateDebugInfoBuilder, variableSlotAllocatorOpt, compilationState, diagnosticsThisMethod, out iteratorStateMachine); StateMachineTypeSymbol stateMachine = iteratorStateMachine; if (!loweredBody.HasErrors) { AsyncStateMachine asyncStateMachine; - loweredBody = AsyncRewriter.Rewrite(loweredBody, method, methodOrdinal, variableSlotAllocatorOpt, compilationState, diagnosticsThisMethod, out asyncStateMachine); + loweredBody = AsyncRewriter.Rewrite(loweredBody, method, methodOrdinal, stateMachineStateDebugInfoBuilder, variableSlotAllocatorOpt, compilationState, diagnosticsThisMethod, out asyncStateMachine); Debug.Assert((object)iteratorStateMachine == null || (object)asyncStateMachine == null); stateMachine = stateMachine ?? asyncStateMachine; @@ -751,6 +757,7 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState) loweredBody, ImmutableArray.Empty, ImmutableArray.Empty, + stateMachineStateDebugInfoBuilder.ToImmutable(), stateMachine, variableSlotAllocatorOpt, diagnosticsThisMethod, @@ -784,11 +791,14 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState) { Debug.Assert(emittedBody is null); } + + stateMachineStateDebugInfoBuilder.Clear(); } } finally { compilationState.CurrentImportChain = oldImportChain; + stateMachineStateDebugInfoBuilder.Free(); } } @@ -868,6 +878,7 @@ private void CompileFieldLikeEventAccessor(SourceEventSymbol eventSymbol, bool i boundBody, ImmutableArray.Empty, ImmutableArray.Empty, + ImmutableArray.Empty, stateMachineTypeOpt: null, variableSlotAllocatorOpt: null, diagnostics: diagnosticsThisMethod, @@ -1185,6 +1196,7 @@ forSemanticModel.Syntax is { } semanticModelSyntax && StateMachineTypeSymbol stateMachineTypeOpt = null; var lambdaDebugInfoBuilder = ArrayBuilder.GetInstance(); var closureDebugInfoBuilder = ArrayBuilder.GetInstance(); + var stateMachineStateDebugInfoBuilder = ArrayBuilder.GetInstance(); BoundStatement loweredBodyOpt = null; try @@ -1204,6 +1216,7 @@ forSemanticModel.Syntax is { } semanticModelSyntax && ref lazyVariableSlotAllocator, lambdaDebugInfoBuilder, closureDebugInfoBuilder, + stateMachineStateDebugInfoBuilder, out stateMachineTypeOpt); Debug.Assert(loweredBodyOpt != null); @@ -1256,6 +1269,7 @@ forSemanticModel.Syntax is { } semanticModelSyntax && ref lazyVariableSlotAllocator, lambdaDebugInfoBuilder, closureDebugInfoBuilder, + stateMachineStateDebugInfoBuilder, out initializerStateMachineTypeOpt); processedInitializers.LoweredInitializers = lowered; @@ -1316,6 +1330,7 @@ forSemanticModel.Syntax is { } semanticModelSyntax && boundBody, lambdaDebugInfoBuilder.ToImmutable(), closureDebugInfoBuilder.ToImmutable(), + stateMachineStateDebugInfoBuilder.ToImmutable(), stateMachineTypeOpt, lazyVariableSlotAllocator, diagsForCurrentMethod, @@ -1336,6 +1351,7 @@ forSemanticModel.Syntax is { } semanticModelSyntax && { lambdaDebugInfoBuilder.Free(); closureDebugInfoBuilder.Free(); + stateMachineStateDebugInfoBuilder.Free(); } } finally @@ -1359,6 +1375,7 @@ internal static BoundStatement LowerBodyOrInitializer( ref VariableSlotAllocator lazyVariableSlotAllocator, ArrayBuilder lambdaDebugInfoBuilder, ArrayBuilder closureDebugInfoBuilder, + ArrayBuilder stateMachineStateDebugInfoBuilder, out StateMachineTypeSymbol stateMachineTypeOpt) { Debug.Assert(compilationState.ModuleBuilderOpt != null); @@ -1413,10 +1430,7 @@ internal static BoundStatement LowerBodyOrInitializer( return loweredBody; } - if (lazyVariableSlotAllocator == null) - { - lazyVariableSlotAllocator = compilationState.ModuleBuilderOpt.TryCreateVariableSlotAllocator(method, method, diagnostics.DiagnosticBag); - } + lazyVariableSlotAllocator ??= compilationState.ModuleBuilderOpt.TryCreateVariableSlotAllocator(method, method, diagnostics.DiagnosticBag); BoundStatement bodyWithoutLambdas = loweredBody; if (sawLambdas || sawLocalFunctions) @@ -1441,7 +1455,7 @@ internal static BoundStatement LowerBodyOrInitializer( return bodyWithoutLambdas; } - BoundStatement bodyWithoutIterators = IteratorRewriter.Rewrite(bodyWithoutLambdas, method, methodOrdinal, lazyVariableSlotAllocator, compilationState, diagnostics, + BoundStatement bodyWithoutIterators = IteratorRewriter.Rewrite(bodyWithoutLambdas, method, methodOrdinal, stateMachineStateDebugInfoBuilder, lazyVariableSlotAllocator, compilationState, diagnostics, out IteratorStateMachine iteratorStateMachine); if (bodyWithoutIterators.HasErrors) @@ -1449,7 +1463,7 @@ internal static BoundStatement LowerBodyOrInitializer( return bodyWithoutIterators; } - BoundStatement bodyWithoutAsync = AsyncRewriter.Rewrite(bodyWithoutIterators, method, methodOrdinal, lazyVariableSlotAllocator, compilationState, diagnostics, + BoundStatement bodyWithoutAsync = AsyncRewriter.Rewrite(bodyWithoutIterators, method, methodOrdinal, stateMachineStateDebugInfoBuilder, lazyVariableSlotAllocator, compilationState, diagnostics, out AsyncStateMachine asyncStateMachine); Debug.Assert((object)iteratorStateMachine == null || (object)asyncStateMachine == null); @@ -1474,6 +1488,7 @@ private static MethodBody GenerateMethodBody( BoundStatement block, ImmutableArray lambdaDebugInfo, ImmutableArray closureDebugInfo, + ImmutableArray stateMachineStateDebugInfos, StateMachineTypeSymbol stateMachineTypeOpt, VariableSlotAllocator variableSlotAllocatorOpt, BindingDiagnosticBag diagnostics, @@ -1623,6 +1638,7 @@ private static MethodBody GenerateMethodBody( stateMachineHoistedLocalScopes, stateMachineHoistedLocalSlots, stateMachineAwaiterSlots, + StateMachineStatesDebugInfo.Create(variableSlotAllocatorOpt, stateMachineStateDebugInfos), moveNextBodyDebugInfoOpt, dynamicAnalysisDataOpt); } diff --git a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpDefinitionMap.cs b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpDefinitionMap.cs index 893d1b9130241..024eafe5e7b33 100644 --- a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpDefinitionMap.cs +++ b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpDefinitionMap.cs @@ -192,17 +192,8 @@ protected override ImmutableArray GetLocalSlotMapFromMetadata(Stan return result; } - protected override ITypeSymbolInternal? TryGetStateMachineType(EntityHandle methodHandle) - { - string typeName; - if (_metadataDecoder.Module.HasStringValuedAttribute(methodHandle, AttributeDescription.AsyncStateMachineAttribute, out typeName) || - _metadataDecoder.Module.HasStringValuedAttribute(methodHandle, AttributeDescription.IteratorStateMachineAttribute, out typeName)) - { - return _metadataDecoder.GetTypeSymbolForSerializedType(typeName); - } - - return null; - } + protected override ITypeSymbolInternal? TryGetStateMachineType(MethodDefinitionHandle methodHandle) + => _metadataDecoder.Module.HasStateMachineAttribute(methodHandle, out var typeName) ? _metadataDecoder.GetTypeSymbolForSerializedType(typeName) : null; /// /// Match local declarations to names to generate a map from diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncExceptionHandlerRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncExceptionHandlerRewriter.cs index e070c6be33c39..d8c903fd0d847 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncExceptionHandlerRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncExceptionHandlerRewriter.cs @@ -135,13 +135,7 @@ public override BoundNode VisitTryStatement(BoundTryStatement node) var tryStatementSyntax = node.Syntax; // If you add a syntax kind to the assertion below, please also ensure // that the scenario has been tested with Edit-and-Continue. - Debug.Assert( - tryStatementSyntax.IsKind(SyntaxKind.TryStatement) || - tryStatementSyntax.IsKind(SyntaxKind.UsingStatement) || - tryStatementSyntax.IsKind(SyntaxKind.ForEachStatement) || - tryStatementSyntax.IsKind(SyntaxKind.ForEachVariableStatement) || - tryStatementSyntax.IsKind(SyntaxKind.LocalDeclarationStatement) || - tryStatementSyntax.IsKind(SyntaxKind.LockStatement)); + Debug.Assert(SyntaxBindingUtilities.BindsToTryStatement(tryStatementSyntax)); BoundStatement finalizedRegion; BoundBlock rewrittenFinally; @@ -711,7 +705,7 @@ public override BoundNode VisitLocalFunctionStatement(BoundLocalFunctionStatemen private AwaitFinallyFrame PushFrame(BoundTryStatement statement) { - var newFrame = new AwaitFinallyFrame(_currentAwaitFinallyFrame, _analysis.Labels(statement), (StatementSyntax)statement.Syntax); + var newFrame = new AwaitFinallyFrame(_currentAwaitFinallyFrame, _analysis.Labels(statement), statement.Syntax); _currentAwaitFinallyFrame = newFrame; return newFrame; } @@ -890,7 +884,7 @@ private sealed class AwaitFinallyFrame public readonly HashSet LabelsOpt; // the try or using-await statement the frame is associated with - private readonly StatementSyntax _statementSyntaxOpt; + private readonly SyntaxNode _syntaxOpt; // proxy labels for branches leaving the frame. // we build this on demand once we encounter leaving branches. @@ -909,20 +903,16 @@ public AwaitFinallyFrame() // root frame } - public AwaitFinallyFrame(AwaitFinallyFrame parent, HashSet labelsOpt, StatementSyntax statementSyntax) + public AwaitFinallyFrame(AwaitFinallyFrame parent, HashSet labelsOpt, SyntaxNode syntax) { Debug.Assert(parent != null); - Debug.Assert(statementSyntax != null); + Debug.Assert(syntax != null); - Debug.Assert(statementSyntax.Kind() == SyntaxKind.TryStatement || - (statementSyntax.Kind() == SyntaxKind.UsingStatement && ((UsingStatementSyntax)statementSyntax).AwaitKeyword != default) || - (statementSyntax.Kind() == SyntaxKind.ForEachStatement && ((CommonForEachStatementSyntax)statementSyntax).AwaitKeyword != default) || - (statementSyntax.Kind() == SyntaxKind.ForEachVariableStatement && ((CommonForEachStatementSyntax)statementSyntax).AwaitKeyword != default) || - (statementSyntax.Kind() == SyntaxKind.LocalDeclarationStatement && ((LocalDeclarationStatementSyntax)statementSyntax).AwaitKeyword != default)); + Debug.Assert(SyntaxBindingUtilities.BindsToTryStatement(syntax)); this.ParentOpt = parent; this.LabelsOpt = labelsOpt; - _statementSyntaxOpt = statementSyntax; + _syntaxOpt = syntax; } public bool IsRoot() @@ -983,8 +973,8 @@ public LabelSymbol ProxyReturnIfNeeded( returnValue = this.returnValue; if (returnValue == null) { - Debug.Assert(_statementSyntaxOpt != null); - this.returnValue = returnValue = new SynthesizedLocal(containingMethod, TypeWithAnnotations.Create(valueOpt.Type), SynthesizedLocalKind.AsyncMethodReturnValue, _statementSyntaxOpt); + Debug.Assert(_syntaxOpt != null); + this.returnValue = returnValue = new SynthesizedLocal(containingMethod, TypeWithAnnotations.Create(valueOpt.Type), SynthesizedLocalKind.AsyncMethodReturnValue, _syntaxOpt); } } diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncIteratorMethodToStateMachineRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncIteratorMethodToStateMachineRewriter.cs index 704f12678935d..6a5506952a903 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncIteratorMethodToStateMachineRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncIteratorMethodToStateMachineRewriter.cs @@ -41,9 +41,9 @@ internal sealed class AsyncIteratorMethodToStateMachineRewriter : AsyncMethodToS private readonly LabelSymbol _exprReturnLabelTrue; /// - /// States for `yield return` are decreasing from -3. + /// States for `yield return` are decreasing from . /// - private int _nextYieldReturnState = StateMachineStates.InitialAsyncIteratorStateMachine; // -3 + private readonly ResumableStateMachineStateAllocator _iteratorStateAllocator; internal AsyncIteratorMethodToStateMachineRewriter(MethodSymbol method, int methodOrdinal, @@ -55,20 +55,40 @@ internal AsyncIteratorMethodToStateMachineRewriter(MethodSymbol method, IReadOnlySet hoistedVariables, IReadOnlyDictionary nonReusableLocalProxies, SynthesizedLocalOrdinalsDispenser synthesizedLocalOrdinals, + ArrayBuilder stateMachineStateDebugInfoBuilder, VariableSlotAllocator slotAllocatorOpt, int nextFreeHoistedLocalSlot, BindingDiagnosticBag diagnostics) : base(method, methodOrdinal, asyncMethodBuilderMemberCollection, F, state, builder, hoistedVariables, nonReusableLocalProxies, synthesizedLocalOrdinals, - slotAllocatorOpt, nextFreeHoistedLocalSlot, diagnostics) + stateMachineStateDebugInfoBuilder, slotAllocatorOpt, nextFreeHoistedLocalSlot, diagnostics) { Debug.Assert(asyncIteratorInfo != null); _asyncIteratorInfo = asyncIteratorInfo; _currentDisposalLabel = _exprReturnLabel; _exprReturnLabelTrue = F.GenerateLabel("yieldReturn"); + + _iteratorStateAllocator = new ResumableStateMachineStateAllocator( + slotAllocatorOpt, + firstState: StateMachineStates.FirstResumableAsyncIteratorState, + increasing: false); } +#nullable enable + protected override BoundStatement? GenerateMissingStateDispatch() + { + var asyncDispatch = base.GenerateMissingStateDispatch(); + + var iteratorDispatch = _iteratorStateAllocator.GenerateThrowMissingStateDispatch(F, F.Local(cachedState), CodeAnalysisResources.EncCannotResumeSuspendedIteratorMethod); + if (iteratorDispatch == null) + { + return asyncDispatch; + } + + return (asyncDispatch != null) ? F.Block(asyncDispatch, iteratorDispatch) : iteratorDispatch; + } +#nullable disable protected override BoundStatement GenerateSetResultCall() { // ... _exprReturnLabel: ... @@ -197,7 +217,7 @@ protected override BoundBinaryOperator ShouldEnterFinallyBlock() // We don't care about state = -2 (method already completed) // So we only want to enter the finally when the state is -1 - return F.IntEqual(F.Local(cachedState), F.Literal(StateMachineStates.NotStartedStateMachine)); + return F.IntEqual(F.Local(cachedState), F.Literal(StateMachineStates.NotStartedOrRunningState)); } #region Visitors @@ -216,9 +236,7 @@ protected override BoundStatement VisitBody(BoundStatement body) // this.state = cachedState = -1; // ... rewritten body - var initialState = _nextYieldReturnState--; - Debug.Assert(initialState == -3); - AddState(initialState, out GeneratedLabelSymbol resumeLabel); + AddState(StateMachineStates.InitialAsyncIteratorState, out GeneratedLabelSymbol resumeLabel); var rewrittenBody = (BoundStatement)Visit(body); @@ -226,7 +244,7 @@ protected override BoundStatement VisitBody(BoundStatement body) return F.Block( F.Label(resumeLabel), // initialStateResumeLabel: GenerateJumpToCurrentDisposalLabel(), // if (disposeMode) goto _exprReturnLabel; - GenerateSetBothStates(StateMachineStates.NotStartedStateMachine), // this.state = cachedState = -1; + GenerateSetBothStates(StateMachineStates.NotStartedOrRunningState), // this.state = cachedState = -1; rewrittenBody); } @@ -245,8 +263,7 @@ public override BoundNode VisitYieldReturnStatement(BoundYieldReturnStatement no // _promiseOfValueOrEnd.SetResult(true); // return; - var stateNumber = _nextYieldReturnState--; - AddState(stateNumber, out GeneratedLabelSymbol resumeLabel); + AddResumableState(_iteratorStateAllocator, node.Syntax, out var stateNumber, out GeneratedLabelSymbol resumeLabel); var rewrittenExpression = (BoundExpression)Visit(node.Expression); var blockBuilder = ArrayBuilder.GetInstance(); @@ -271,7 +288,7 @@ public override BoundNode VisitYieldReturnStatement(BoundYieldReturnStatement no blockBuilder.Add( // this.state = cachedState = NotStartedStateMachine - GenerateSetBothStates(StateMachineStates.NotStartedStateMachine)); + GenerateSetBothStates(StateMachineStates.NotStartedOrRunningState)); Debug.Assert(_currentDisposalLabel is object); // no yield return allowed inside a finally blockBuilder.Add( diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs index 54d51eeb76004..65634991addeb 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs @@ -74,10 +74,11 @@ internal AsyncMethodToStateMachineRewriter( IReadOnlySet hoistedVariables, IReadOnlyDictionary nonReusableLocalProxies, SynthesizedLocalOrdinalsDispenser synthesizedLocalOrdinals, + ArrayBuilder stateMachineStateDebugInfoBuilder, VariableSlotAllocator slotAllocatorOpt, int nextFreeHoistedLocalSlot, BindingDiagnosticBag diagnostics) - : base(F, method, state, hoistedVariables, nonReusableLocalProxies, synthesizedLocalOrdinals, slotAllocatorOpt, nextFreeHoistedLocalSlot, diagnostics) + : base(F, method, state, hoistedVariables, nonReusableLocalProxies, synthesizedLocalOrdinals, stateMachineStateDebugInfoBuilder, slotAllocatorOpt, nextFreeHoistedLocalSlot, diagnostics) { _method = method; _asyncMethodBuilderMemberCollection = asyncMethodBuilderMemberCollection; @@ -120,6 +121,12 @@ private FieldSymbol GetAwaiterField(TypeSymbol awaiterType) return result; } + protected sealed override string EncMissingStateMessage + => CodeAnalysisResources.EncCannotResumeSuspendedAsyncMethod; + + protected sealed override int FirstIncreasingResumableState + => StateMachineStates.FirstResumableAsyncState; + /// /// Generate the body for MoveNext(). /// @@ -143,7 +150,7 @@ internal void GenerateMoveNext(BoundStatement body, MethodSymbol moveNextMethod) F.Block(ImmutableArray.Empty, // switch (state) ... F.HiddenSequencePoint(), - Dispatch(), + Dispatch(isOutermost: true), // [body] rewrittenBody ), @@ -154,7 +161,7 @@ internal void GenerateMoveNext(BoundStatement body, MethodSymbol moveNextMethod) bodyBuilder.Add(F.Label(_exprReturnLabel)); // this.state = finishedState - var stateDone = F.Assignment(F.Field(F.This(), stateField), F.Literal(StateMachineStates.FinishedStateMachine)); + var stateDone = F.Assignment(F.Field(F.This(), stateField), F.Literal(StateMachineStates.FinishedState)); var block = body.Syntax as BlockSyntax; if (block == null) { @@ -228,7 +235,7 @@ protected BoundCatchBlock GenerateExceptionHandling(LocalSymbol exceptionLocal, // _state = finishedState; BoundStatement assignFinishedState = - F.ExpressionStatement(F.AssignmentExpression(F.Field(F.This(), stateField), F.Literal(StateMachineStates.FinishedStateMachine))); + F.ExpressionStatement(F.AssignmentExpression(F.Field(F.This(), stateField), F.Literal(StateMachineStates.FinishedState))); // builder.SetException(ex); OR if (this.combinedTokens != null) this.combinedTokens.Dispose(); _promiseOfValueOrEnd.SetException(ex); BoundStatement callSetException = GenerateSetExceptionCall(exceptionLocal); @@ -436,7 +443,7 @@ private BoundExpression GenerateGetIsCompleted(LocalSymbol awaiterTemp, MethodSy private BoundBlock GenerateAwaitForIncompleteTask(LocalSymbol awaiterTemp) { - AddState(out int stateNumber, out GeneratedLabelSymbol resumeLabel); + AddResumableState(awaiterTemp.GetDeclaratorSyntax(), out int stateNumber, out GeneratedLabelSymbol resumeLabel); TypeSymbol awaiterFieldType = awaiterTemp.Type.IsVerifierReference() ? F.SpecialType(SpecialType.System_Object) @@ -490,7 +497,7 @@ private BoundBlock GenerateAwaitForIncompleteTask(LocalSymbol awaiterTemp) blockBuilder.Add( // this.state = cachedState = NotStartedStateMachine - GenerateSetBothStates(StateMachineStates.NotStartedStateMachine)); + GenerateSetBothStates(StateMachineStates.NotStartedOrRunningState)); return F.Block(blockBuilder.ToImmutableAndFree()); } diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncRewriter.AsyncIteratorRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncRewriter.AsyncIteratorRewriter.cs index e445aec99d928..d65f85549dbca 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncRewriter.AsyncIteratorRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncRewriter.AsyncIteratorRewriter.cs @@ -36,10 +36,11 @@ internal AsyncIteratorRewriter( MethodSymbol method, int methodOrdinal, AsyncStateMachine stateMachineType, + ArrayBuilder stateMachineStateDebugInfoBuilder, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics) - : base(body, method, methodOrdinal, stateMachineType, slotAllocatorOpt, compilationState, diagnostics) + : base(body, method, methodOrdinal, stateMachineType, stateMachineStateDebugInfoBuilder, slotAllocatorOpt, compilationState, diagnostics) { Debug.Assert(!TypeSymbol.Equals(method.IteratorElementTypeWithAnnotations.Type, null, TypeCompareKind.ConsiderEverything2)); @@ -194,7 +195,7 @@ private BoundExpressionStatement GenerateCreateAndAssignBuilder() protected override void InitializeStateMachine(ArrayBuilder bodyBuilder, NamedTypeSymbol frameType, LocalSymbol stateMachineLocal) { // var stateMachineLocal = new {StateMachineType}({initialState}) - int initialState = _isEnumerable ? StateMachineStates.FinishedStateMachine : StateMachineStates.InitialAsyncIteratorStateMachine; + int initialState = _isEnumerable ? StateMachineStates.FinishedState : StateMachineStates.InitialAsyncIteratorState; bodyBuilder.Add( F.Assignment( F.Local(stateMachineLocal), @@ -322,7 +323,7 @@ private void GenerateIAsyncEnumeratorImplementation_MoveNextAsync() BoundStatement ifFinished = F.If( // if (state == StateMachineStates.FinishedStateMachine) - F.IntEqual(F.InstanceField(stateField), F.Literal(StateMachineStates.FinishedStateMachine)), + F.IntEqual(F.InstanceField(stateField), F.Literal(StateMachineStates.FinishedState)), // return default; thenClause: F.Return(F.Default(moveNextAsyncReturnType))); @@ -432,13 +433,13 @@ private void GenerateIAsyncDisposable_DisposeAsync() BoundStatement ifInvalidState = F.If( // if (state >= StateMachineStates.NotStartedStateMachine /* -1 */) - F.IntGreaterThanOrEqual(F.InstanceField(stateField), F.Literal(StateMachineStates.NotStartedStateMachine)), + F.IntGreaterThanOrEqual(F.InstanceField(stateField), F.Literal(StateMachineStates.NotStartedOrRunningState)), // throw new NotSupportedException(); thenClause: F.Throw(F.New(F.WellKnownType(WellKnownType.System_NotSupportedException)))); BoundStatement ifFinished = F.If( // if (state == StateMachineStates.FinishedStateMachine) - F.IntEqual(F.InstanceField(stateField), F.Literal(StateMachineStates.FinishedStateMachine)), + F.IntEqual(F.InstanceField(stateField), F.Literal(StateMachineStates.FinishedState)), // return default; thenClause: F.Return(F.Default(returnType))); @@ -650,7 +651,7 @@ private void GenerateIAsyncEnumerableImplementation_GetAsyncEnumerator() .AsMember(IAsyncEnumerableOfElementType); BoundExpression managedThreadId = null; - GenerateIteratorGetEnumerator(IAsyncEnumerableOfElementType_GetEnumerator, ref managedThreadId, initialState: StateMachineStates.InitialAsyncIteratorStateMachine); + GenerateIteratorGetEnumerator(IAsyncEnumerableOfElementType_GetEnumerator, ref managedThreadId, initialState: StateMachineStates.InitialAsyncIteratorState); } protected override void GenerateResetInstance(ArrayBuilder builder, int initialState) @@ -697,6 +698,7 @@ protected override void GenerateMoveNext(SynthesizedImplementationMethod moveNex hoistedVariables: hoistedVariables, nonReusableLocalProxies: nonReusableLocalProxies, synthesizedLocalOrdinals: synthesizedLocalOrdinals, + stateMachineStateDebugInfoBuilder, slotAllocatorOpt: slotAllocatorOpt, nextFreeHoistedLocalSlot: nextFreeHoistedLocalSlot, diagnostics: diagnostics); diff --git a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncRewriter.cs index d26488e5948d7..6616076c64846 100644 --- a/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncRewriter.cs @@ -25,10 +25,11 @@ private AsyncRewriter( MethodSymbol method, int methodOrdinal, AsyncStateMachine stateMachineType, + ArrayBuilder stateMachineStateDebugInfoBuilder, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics) - : base(body, method, stateMachineType, slotAllocatorOpt, compilationState, diagnostics) + : base(body, method, stateMachineType, stateMachineStateDebugInfoBuilder, slotAllocatorOpt, compilationState, diagnostics) { _constructedSuccessfully = AsyncMethodBuilderMemberCollection.TryCreate(F, method, this.stateMachineType.TypeMap, out _asyncMethodBuilderMemberCollection); _methodOrdinal = methodOrdinal; @@ -41,6 +42,7 @@ internal static BoundStatement Rewrite( BoundStatement bodyWithAwaitLifted, MethodSymbol method, int methodOrdinal, + ArrayBuilder stateMachineStateDebugInfoBuilder, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics, @@ -73,8 +75,8 @@ internal static BoundStatement Rewrite( compilationState.ModuleBuilderOpt.CompilationState.SetStateMachineType(method, stateMachineType); AsyncRewriter rewriter = isAsyncEnumerableOrEnumerator - ? new AsyncIteratorRewriter(bodyWithAwaitLifted, method, methodOrdinal, stateMachineType, slotAllocatorOpt, compilationState, diagnostics) - : new AsyncRewriter(bodyWithAwaitLifted, method, methodOrdinal, stateMachineType, slotAllocatorOpt, compilationState, diagnostics); + ? new AsyncIteratorRewriter(bodyWithAwaitLifted, method, methodOrdinal, stateMachineType, stateMachineStateDebugInfoBuilder, slotAllocatorOpt, compilationState, diagnostics) + : new AsyncRewriter(bodyWithAwaitLifted, method, methodOrdinal, stateMachineType, stateMachineStateDebugInfoBuilder, slotAllocatorOpt, compilationState, diagnostics); if (!rewriter.VerifyPresenceOfRequiredAPIs()) { @@ -228,7 +230,7 @@ protected override BoundStatement GenerateStateMachineCreation(LocalSymbol state bodyBuilder.Add( F.Assignment( F.Field(F.Local(stateMachineVariable), stateField.AsMember(frameType)), - F.Literal(StateMachineStates.NotStartedStateMachine))); + F.Literal(StateMachineStates.NotStartedOrRunningState))); // local.$builder.Start(ref local) -- binding to the method AsyncTaskMethodBuilder.Start() var startMethod = methodScopeAsyncMethodBuilderMemberCollection.Start.Construct(frameType); @@ -265,6 +267,7 @@ protected virtual void GenerateMoveNext(SynthesizedImplementationMethod moveNext hoistedVariables: hoistedVariables, nonReusableLocalProxies: nonReusableLocalProxies, synthesizedLocalOrdinals: synthesizedLocalOrdinals, + stateMachineStateDebugInfoBuilder, slotAllocatorOpt: slotAllocatorOpt, nextFreeHoistedLocalSlot: nextFreeHoistedLocalSlot, diagnostics: diagnostics); diff --git a/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorMethodToStateMachineRewriter.IteratorFinallyFrame.cs b/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorMethodToStateMachineRewriter.IteratorFinallyFrame.cs index d1acb500db5af..24656238528aa 100644 --- a/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorMethodToStateMachineRewriter.IteratorFinallyFrame.cs +++ b/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorMethodToStateMachineRewriter.IteratorFinallyFrame.cs @@ -57,7 +57,7 @@ public IteratorFinallyFrame( public IteratorFinallyFrame() { - this.finalizeState = StateMachineStates.NotStartedStateMachine; + this.finalizeState = StateMachineStates.NotStartedOrRunningState; } public bool IsRoot() diff --git a/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorMethodToStateMachineRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorMethodToStateMachineRewriter.cs index 8de0bbf1aba92..2b647596d65c3 100644 --- a/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorMethodToStateMachineRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorMethodToStateMachineRewriter.cs @@ -53,7 +53,7 @@ internal sealed partial class IteratorMethodToStateMachineRewriter : MethodToSta /// The purpose of distinct finally states is to have enough information about /// which finally handlers must run when we need to finalize iterator after a fault. /// - private int _nextFinalizeState = StateMachineStates.FinishedStateMachine - 1; // -3 + private int _nextFinalizeState; internal IteratorMethodToStateMachineRewriter( SyntheticBoundNodeFactory F, @@ -63,14 +63,23 @@ internal IteratorMethodToStateMachineRewriter( IReadOnlySet hoistedVariables, IReadOnlyDictionary nonReusableLocalProxies, SynthesizedLocalOrdinalsDispenser synthesizedLocalOrdinals, + ArrayBuilder stateMachineStateDebugInfoBuilder, VariableSlotAllocator slotAllocatorOpt, int nextFreeHoistedLocalSlot, BindingDiagnosticBag diagnostics) - : base(F, originalMethod, state, hoistedVariables, nonReusableLocalProxies, synthesizedLocalOrdinals, slotAllocatorOpt, nextFreeHoistedLocalSlot, diagnostics) + : base(F, originalMethod, state, hoistedVariables, nonReusableLocalProxies, synthesizedLocalOrdinals, stateMachineStateDebugInfoBuilder, slotAllocatorOpt, nextFreeHoistedLocalSlot, diagnostics) { _current = current; + + _nextFinalizeState = slotAllocatorOpt?.GetFirstUnusedStateMachineState(increasing: false) ?? StateMachineStates.FirstIteratorFinalizeState; } + protected override string EncMissingStateMessage + => CodeAnalysisResources.EncCannotResumeSuspendedIteratorMethod; + + protected override int FirstIncreasingResumableState + => StateMachineStates.FirstResumableIteratorState; + internal void GenerateMoveNextAndDispose(BoundStatement body, SynthesizedImplementationMethod moveNextMethod, SynthesizedImplementationMethod disposeMethod) { // scan body for yielding try blocks @@ -86,9 +95,7 @@ internal void GenerateMoveNextAndDispose(BoundStatement body, SynthesizedImpleme /////////////////////////////////// F.CurrentFunction = moveNextMethod; - int initialState; - GeneratedLabelSymbol initialLabel; - AddState(out initialState, out initialLabel); + AddState(StateMachineStates.InitialIteratorState, out GeneratedLabelSymbol initialLabel); var newBody = (BoundStatement)Visit(body); // switch(cachedState) { @@ -108,10 +115,10 @@ internal void GenerateMoveNextAndDispose(BoundStatement body, SynthesizedImpleme F.HiddenSequencePoint(), F.Assignment(F.Local(cachedState), F.Field(F.This(), stateField)), CacheThisIfNeeded(), - Dispatch(), + Dispatch(isOutermost: true), GenerateReturn(finished: true), F.Label(initialLabel), - F.Assignment(F.Field(F.This(), stateField), F.Literal(StateMachineStates.NotStartedStateMachine)), + F.Assignment(F.Field(F.This(), stateField), F.Literal(StateMachineStates.NotStartedOrRunningState)), newBody); // @@ -321,9 +328,7 @@ public override BoundNode VisitYieldReturnStatement(BoundYieldReturnStatement no // : ; // // this.state = finalizeState; - int stateNumber; - GeneratedLabelSymbol resumeLabel; - AddState(out stateNumber, out resumeLabel); + AddResumableState(node.Syntax, out int stateNumber, out GeneratedLabelSymbol resumeLabel); _currentFinallyFrame.AddState(stateNumber); var rewrittenExpression = (BoundExpression)Visit(node.Expression); @@ -453,11 +458,18 @@ public override BoundNode VisitTryStatement(BoundTryStatement node) private IteratorFinallyFrame PushFrame(BoundTryStatement statement) { - var state = _nextFinalizeState--; + var syntax = statement.Syntax; + + if (slotAllocatorOpt?.TryGetPreviousStateMachineState(syntax, out var finalizeState) != true) + { + finalizeState = _nextFinalizeState--; + } + + AddStateDebugInfo(syntax, finalizeState); - var finallyMethod = MakeSynthesizedFinally(state); - var newFrame = new IteratorFinallyFrame(_currentFinallyFrame, state, finallyMethod, _yieldsInTryAnalysis.Labels(statement)); - newFrame.AddState(state); + var finallyMethod = MakeSynthesizedFinally(finalizeState); + var newFrame = new IteratorFinallyFrame(_currentFinallyFrame, finalizeState, finallyMethod, _yieldsInTryAnalysis.Labels(statement)); + newFrame.AddState(finalizeState); _currentFinallyFrame = newFrame; return newFrame; @@ -474,10 +486,10 @@ private bool ContainsYields(BoundTryStatement statement) return _yieldsInTryAnalysis.ContainsYields(statement); } - private IteratorFinallyMethodSymbol MakeSynthesizedFinally(int state) + private IteratorFinallyMethodSymbol MakeSynthesizedFinally(int finalizeState) { var stateMachineType = (IteratorStateMachine)F.CurrentType; - var finallyMethod = new IteratorFinallyMethodSymbol(stateMachineType, GeneratedNames.MakeIteratorFinallyMethodName(state)); + var finallyMethod = new IteratorFinallyMethodSymbol(stateMachineType, GeneratedNames.MakeIteratorFinallyMethodName(finalizeState)); F.ModuleBuilderOpt.AddSynthesizedDefinition(stateMachineType, finallyMethod.GetCciAdapter()); return finallyMethod; diff --git a/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorRewriter.cs index 4c3ab2c33e4b2..a1429a11033e7 100644 --- a/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorRewriter.cs @@ -30,10 +30,11 @@ private IteratorRewriter( MethodSymbol method, bool isEnumerable, IteratorStateMachine stateMachineType, + ArrayBuilder stateMachineStateDebugInfoBuilder, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics) - : base(body, method, stateMachineType, slotAllocatorOpt, compilationState, diagnostics) + : base(body, method, stateMachineType, stateMachineStateDebugInfoBuilder, slotAllocatorOpt, compilationState, diagnostics) { // the element type may contain method type parameters, which are now alpha-renamed into type parameters of the generated class _elementType = stateMachineType.ElementType; @@ -48,6 +49,7 @@ internal static BoundStatement Rewrite( BoundStatement body, MethodSymbol method, int methodOrdinal, + ArrayBuilder stateMachineStateDebugInfoBuilder, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics, @@ -80,7 +82,7 @@ internal static BoundStatement Rewrite( stateMachineType = new IteratorStateMachine(slotAllocatorOpt, compilationState, method, methodOrdinal, isEnumerable, elementType); compilationState.ModuleBuilderOpt.CompilationState.SetStateMachineType(method, stateMachineType); - var rewriter = new IteratorRewriter(body, method, isEnumerable, stateMachineType, slotAllocatorOpt, compilationState, diagnostics); + var rewriter = new IteratorRewriter(body, method, isEnumerable, stateMachineType, stateMachineStateDebugInfoBuilder, slotAllocatorOpt, compilationState, diagnostics); if (!rewriter.VerifyPresenceOfRequiredAPIs()) { return body; @@ -248,7 +250,7 @@ private void GenerateEnumerableImplementation(ref BoundExpression managedThreadI var IEnumerableOfElementType_GetEnumerator = F.SpecialMethod(SpecialMember.System_Collections_Generic_IEnumerable_T__GetEnumerator).AsMember(IEnumerableOfElementType); // generate GetEnumerator() - var getEnumeratorGeneric = GenerateIteratorGetEnumerator(IEnumerableOfElementType_GetEnumerator, ref managedThreadId, StateMachineStates.FirstUnusedState); + var getEnumeratorGeneric = GenerateIteratorGetEnumerator(IEnumerableOfElementType_GetEnumerator, ref managedThreadId, StateMachineStates.InitialIteratorState); // Generate IEnumerable.GetEnumerator var getEnumerator = OpenMethodImplementation(IEnumerable_GetEnumerator); @@ -285,7 +287,7 @@ protected override void InitializeStateMachine(ArrayBuilder body { // var stateMachineLocal = new IteratorImplementationClass(N) // where N is either 0 (if we're producing an enumerator) or -2 (if we're producing an enumerable) - int initialState = _isEnumerable ? StateMachineStates.FinishedStateMachine : StateMachineStates.FirstUnusedState; + int initialState = _isEnumerable ? StateMachineStates.FinishedState : StateMachineStates.InitialIteratorState; bodyBuilder.Add( F.Assignment( F.Local(stateMachineLocal), @@ -318,6 +320,7 @@ private void GenerateMoveNextAndDispose( hoistedVariables, nonReusableLocalProxies, synthesizedLocalOrdinals, + stateMachineStateDebugInfoBuilder, slotAllocatorOpt, nextFreeHoistedLocalSlot, diagnostics); diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UsingStatement.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UsingStatement.cs index 4a7083be57f42..41ecea365c121 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UsingStatement.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UsingStatement.cs @@ -186,7 +186,7 @@ private BoundBlock MakeExpressionUsingStatement(BoundUsingStatement node, BoundB expressionStatement = _instrumenter.InstrumentUsingTargetCapture(node, expressionStatement); } - BoundStatement tryFinally = RewriteUsingStatementTryFinally(usingSyntax, tryBlock, boundTemp, usingSyntax.AwaitKeyword, node.AwaitOpt, node.PatternDisposeInfoOpt); + BoundStatement tryFinally = RewriteUsingStatementTryFinally(usingSyntax, usingSyntax, tryBlock, boundTemp, usingSyntax.AwaitKeyword, node.AwaitOpt, node.PatternDisposeInfoOpt); // { ResourceType temp = expr; try { ... } finally { ... } } return new BoundBlock( @@ -229,7 +229,7 @@ private BoundBlock RewriteDeclarationUsingStatement( if (boundLocal.ConstantValue == ConstantValue.Null) { //localSymbol will be declared by an enclosing block - return BoundBlock.SynthesizedNoLocals(usingSyntax, rewrittenDeclaration, tryBlock); + return BoundBlock.SynthesizedNoLocals(declarationSyntax, rewrittenDeclaration, tryBlock); } if (localType.IsDynamic()) @@ -250,10 +250,10 @@ private BoundBlock RewriteDeclarationUsingStatement( BoundAssignmentOperator tempAssignment; BoundLocal boundTemp = _factory.StoreToTemp(tempInit, out tempAssignment, kind: SynthesizedLocalKind.Using); - BoundStatement tryFinally = RewriteUsingStatementTryFinally(usingSyntax, tryBlock, boundTemp, awaitKeywordOpt, awaitOpt, patternDisposeInfo); + BoundStatement tryFinally = RewriteUsingStatementTryFinally(usingSyntax, declarationSyntax, tryBlock, boundTemp, awaitKeywordOpt, awaitOpt, patternDisposeInfo); return new BoundBlock( - syntax: usingSyntax, + syntax: declarationSyntax, locals: ImmutableArray.Create(boundTemp.LocalSymbol), //localSymbol will be declared by an enclosing block statements: ImmutableArray.Create( rewrittenDeclaration, @@ -262,14 +262,15 @@ private BoundBlock RewriteDeclarationUsingStatement( } else { - BoundStatement tryFinally = RewriteUsingStatementTryFinally(usingSyntax, tryBlock, boundLocal, awaitKeywordOpt, awaitOpt, patternDisposeInfo); + BoundStatement tryFinally = RewriteUsingStatementTryFinally(usingSyntax, declarationSyntax, tryBlock, boundLocal, awaitKeywordOpt, awaitOpt, patternDisposeInfo); // localSymbol will be declared by an enclosing block - return BoundBlock.SynthesizedNoLocals(usingSyntax, rewrittenDeclaration, tryFinally); + return BoundBlock.SynthesizedNoLocals(declarationSyntax, rewrittenDeclaration, tryFinally); } } private BoundStatement RewriteUsingStatementTryFinally( + SyntaxNode typeSyntax, SyntaxNode syntax, BoundBlock tryBlock, BoundLocal local, @@ -352,7 +353,7 @@ private BoundStatement RewriteUsingStatementTryFinally( if (isNullableValueType) { - MethodSymbol getValueOrDefault = UnsafeGetNullableMethod(syntax, local.Type, SpecialMember.System_Nullable_T_GetValueOrDefault); + MethodSymbol getValueOrDefault = UnsafeGetNullableMethod(typeSyntax, local.Type, SpecialMember.System_Nullable_T_GetValueOrDefault); // local.GetValueOrDefault() disposedExpression = BoundCall.Synthesized(syntax, local, getValueOrDefault); } @@ -362,7 +363,7 @@ private BoundStatement RewriteUsingStatementTryFinally( disposedExpression = local; } - BoundExpression disposeCall = GenerateDisposeCall(syntax, disposedExpression, patternDisposeInfo, awaitOpt, awaitKeywordOpt); + BoundExpression disposeCall = GenerateDisposeCall(typeSyntax, syntax, disposedExpression, patternDisposeInfo, awaitOpt, awaitKeywordOpt); // local.Dispose(); or await variant BoundStatement disposeStatement = new BoundExpressionStatement(syntax, disposeCall); @@ -419,6 +420,7 @@ private BoundStatement RewriteUsingStatementTryFinally( } private BoundExpression GenerateDisposeCall( + SyntaxNode typeSyntax, SyntaxNode syntax, BoundExpression disposedExpression, MethodArgumentInfo? disposeInfo, @@ -434,7 +436,7 @@ private BoundExpression GenerateDisposeCall( if (awaitOpt is null) { // IDisposable.Dispose() - Binder.TryGetSpecialTypeMember(_compilation, SpecialMember.System_IDisposable__Dispose, syntax, _diagnostics, out disposeMethod); + Binder.TryGetSpecialTypeMember(_compilation, SpecialMember.System_IDisposable__Dispose, typeSyntax, _diagnostics, out disposeMethod); } else { diff --git a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/MethodToStateMachineRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/MethodToStateMachineRewriter.cs index b0fb061e344da..f9920cb65fbc8 100644 --- a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/MethodToStateMachineRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/MethodToStateMachineRewriter.cs @@ -22,11 +22,6 @@ internal abstract class MethodToStateMachineRewriter : MethodToClassRewriter { internal readonly MethodSymbol OriginalMethod; - /// - /// Generate return statements from the state machine method body. - /// - protected abstract BoundStatement GenerateReturn(bool finished); - protected readonly SyntheticBoundNodeFactory F; /// @@ -56,7 +51,10 @@ internal abstract class MethodToStateMachineRewriter : MethodToClassRewriter /// protected readonly LocalSymbol cachedThis; - private int _nextState; + /// + /// Allocates resumable states, i.e. states that resume execution of the state machine after await expression or yield return. + /// + private readonly ResumableStateMachineStateAllocator _resumableStateAllocator; /// /// For each distinct label, the set of states that need to be dispatched to that label. @@ -90,6 +88,11 @@ internal abstract class MethodToStateMachineRewriter : MethodToClassRewriter private readonly SynthesizedLocalOrdinalsDispenser _synthesizedLocalOrdinals; private int _nextFreeHoistedLocalSlot; + /// + /// EnC support: the rewriter stores debug info for each await/yield in this builder. + /// + private readonly ArrayBuilder _stateDebugInfoBuilder; + // new: public MethodToStateMachineRewriter( SyntheticBoundNodeFactory F, @@ -98,6 +101,7 @@ public MethodToStateMachineRewriter( IReadOnlySet hoistedVariables, IReadOnlyDictionary nonReusableLocalProxies, SynthesizedLocalOrdinalsDispenser synthesizedLocalOrdinals, + ArrayBuilder stateMachineStateDebugInfoBuilder, VariableSlotAllocator slotAllocatorOpt, int nextFreeHoistedLocalSlot, BindingDiagnosticBag diagnostics) @@ -135,8 +139,27 @@ public MethodToStateMachineRewriter( BoundExpression thisProxyReplacement = thisProxy.Replacement(F.Syntax, frameType => F.This()); this.cachedThis = F.SynthesizedLocal(thisProxyReplacement.Type, syntax: F.Syntax, kind: SynthesizedLocalKind.FrameCache); } + + _stateDebugInfoBuilder = stateMachineStateDebugInfoBuilder; + + // Use the first state number that is not used by any previous version of the state machine + // for the first added state that doesn't match any states of the previous state machine. + // Note the initial states of the previous and the current state machine are always the same. + // Note the previous state machine might not have any non-initial states. + _resumableStateAllocator = new ResumableStateMachineStateAllocator( + slotAllocatorOpt, + firstState: FirstIncreasingResumableState, + increasing: true); } + protected abstract int FirstIncreasingResumableState { get; } + protected abstract string EncMissingStateMessage { get; } + + /// + /// Generate return statements from the state machine method body. + /// + protected abstract BoundStatement GenerateReturn(bool finished); + protected override bool NeedsProxy(Symbol localOrParameter) { Debug.Assert(localOrParameter.Kind == SymbolKind.Local || localOrParameter.Kind == SymbolKind.Parameter); @@ -175,33 +198,66 @@ protected override BoundExpression FramePointer(SyntaxNode syntax, NamedTypeSymb F.Syntax = oldSyntax; return result; } +#nullable enable + protected void AddResumableState(SyntaxNode awaitOrYieldReturnSyntax, out int stateNumber, out GeneratedLabelSymbol resumeLabel) + => AddResumableState(_resumableStateAllocator, awaitOrYieldReturnSyntax, out stateNumber, out resumeLabel); - protected void AddState(out int stateNumber, out GeneratedLabelSymbol resumeLabel) + protected void AddResumableState(ResumableStateMachineStateAllocator allocator, SyntaxNode awaitOrYieldReturnSyntax, out int stateNumber, out GeneratedLabelSymbol resumeLabel) { - stateNumber = _nextState++; + stateNumber = allocator.AllocateState(awaitOrYieldReturnSyntax); + AddStateDebugInfo(awaitOrYieldReturnSyntax, stateNumber); AddState(stateNumber, out resumeLabel); } + protected void AddStateDebugInfo(SyntaxNode node, int stateNumber) + { + Debug.Assert(SyntaxBindingUtilities.BindsToResumableStateMachineState(node) || SyntaxBindingUtilities.BindsToTryStatement(node), $"Unexpected syntax: {node.Kind()}"); + + int syntaxOffset = CurrentMethod.CalculateLocalSyntaxOffset(node.SpanStart, node.SyntaxTree); + _stateDebugInfoBuilder.Add(new StateMachineStateDebugInfo(syntaxOffset, stateNumber)); + } + protected void AddState(int stateNumber, out GeneratedLabelSymbol resumeLabel) { - if (_dispatches == null) - { - _dispatches = new Dictionary>(); - } + _dispatches ??= new Dictionary>(); resumeLabel = F.GenerateLabel("stateMachine"); - var states = new List(); - states.Add(stateNumber); - _dispatches.Add(resumeLabel, states); + _dispatches.Add(resumeLabel, new List { stateNumber }); } - protected BoundStatement Dispatch() - { - return F.Switch(F.Local(cachedState), - (from kv in _dispatches orderby kv.Value[0] select F.SwitchSection(kv.Value, F.Goto(kv.Key))).ToImmutableArray() - ); + /// + /// Generates code that switches over states and jumps to the target labels listed in . + /// + /// + /// If this is the outermost state dispatch switching over all states of the state machine - i.e. not state dispatch generated for a try-block. + /// + protected BoundStatement Dispatch(bool isOutermost) + { + var sections = from kv in _dispatches orderby kv.Value[0] select F.SwitchSection(kv.Value, F.Goto(kv.Key)); + var result = F.Switch(F.Local(cachedState), sections.ToImmutableArray()); + + // Suspension states that were generated for any previous generation of the state machine + // but are not present in the current version (awaits/yields have been deleted) need to be dispatched to a throw expression. + // When an instance of previous version of the state machine is suspended in a state that does not exist anymore + // in the current version dispatch that state to a throw expression. We do not know for sure where to resume in the new version of the method. + // Guessing would likely result in unexpected behavior. Resuming in an incorrect point might result in an execution of code that + // has already been executed or skipping code that initializes some user state. + if (isOutermost) + { + var missingStateDispatch = GenerateMissingStateDispatch(); + if (missingStateDispatch != null) + { + result = F.Block(result, missingStateDispatch); + } + } + + return result; } + protected virtual BoundStatement? GenerateMissingStateDispatch() + => _resumableStateAllocator.GenerateThrowMissingStateDispatch(F, F.Local(cachedState), EncMissingStateMessage); + +#nullable disable #if DEBUG public override BoundNode VisitSequence(BoundSequence node) { @@ -775,7 +831,7 @@ public override BoundNode VisitTryStatement(BoundTryStatement node) tryBlock = F.Block( F.HiddenSequencePoint(), - Dispatch(), + Dispatch(isOutermost: false), tryBlock); oldDispatches ??= new Dictionary>(); diff --git a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/ResumableStateMachineStateAllocator.cs b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/ResumableStateMachineStateAllocator.cs new file mode 100644 index 0000000000000..edb186992cd70 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/ResumableStateMachineStateAllocator.cs @@ -0,0 +1,95 @@ +// 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. + +using System; +using System.Diagnostics; +using Microsoft.CodeAnalysis.CodeGen; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Microsoft.CodeAnalysis.CSharp +{ + /// + /// Allocates resumable states, i.e. states that resume execution of the state machine after await expression or yield return. + /// + internal sealed class ResumableStateMachineStateAllocator + { + private readonly VariableSlotAllocator? _slotAllocator; + private readonly bool _increasing; + private readonly int _firstState; + + /// + /// The number of the next generated resumable state (i.e. state that resumes execution of the state machine after await expression or yield return). + /// + private int _nextState; + +#if DEBUG + /// + /// EnC support: states in this state machine that were matched to states of the previous generation state machine. + /// + private BitVector _matchedStates = BitVector.Empty; +#endif + /// + /// EnC support: number of states in this state machine that match states of the previous generation state machine. + /// + private int _matchedStateCount; + + public ResumableStateMachineStateAllocator(VariableSlotAllocator? slotAllocator, int firstState, bool increasing) + { + _increasing = increasing; + _slotAllocator = slotAllocator; + _matchedStateCount = 0; + _firstState = firstState; + _nextState = slotAllocator?.GetFirstUnusedStateMachineState(increasing) ?? firstState; + } + + public int AllocateState(SyntaxNode awaitOrYieldReturnSyntax) + { + Debug.Assert(SyntaxBindingUtilities.BindsToResumableStateMachineState(awaitOrYieldReturnSyntax)); + + int direction = _increasing ? +1 : -1; + + if (_slotAllocator?.TryGetPreviousStateMachineState(awaitOrYieldReturnSyntax, out var stateNumber) == true) + { +#if DEBUG + // two states of the new state machine should not match the same state of the previous machine: + Debug.Assert(!_matchedStates[stateNumber * direction]); + _matchedStates[stateNumber * direction] = true; +#endif + _matchedStateCount++; + } + else + { + stateNumber = _nextState; + _nextState += direction; + } + + return stateNumber; + } + + /// + /// True if any of the states generated for any previous state machine has not been allocated in this version. + /// + public bool HasMissingStates + => _matchedStateCount < Math.Abs((_slotAllocator?.GetFirstUnusedStateMachineState(_increasing) ?? _firstState) - _firstState); + + public BoundStatement? GenerateThrowMissingStateDispatch(SyntheticBoundNodeFactory f, BoundExpression cachedState, string message) + { + if (!HasMissingStates) + { + return null; + } + + return f.If( + f.Binary( + _increasing ? BinaryOperatorKind.IntGreaterThanOrEqual : BinaryOperatorKind.IntLessThanOrEqual, + f.SpecialType(SpecialType.System_Boolean), + cachedState, + f.Literal(_firstState)), + f.Throw( + f.New( + f.WellKnownMethod(WellKnownMember.System_InvalidOperationException__ctorString), + f.StringLiteral(ConstantValue.Create(message))))); + } + } +} diff --git a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.cs index 0616f66995d3a..0ef6f322a3bd2 100644 --- a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.cs @@ -25,6 +25,7 @@ internal abstract class StateMachineRewriter protected readonly SynthesizedContainer stateMachineType; protected readonly VariableSlotAllocator slotAllocatorOpt; protected readonly SynthesizedLocalOrdinalsDispenser synthesizedLocalOrdinals; + protected readonly ArrayBuilder stateMachineStateDebugInfoBuilder; protected FieldSymbol stateField; protected IReadOnlyDictionary nonReusableLocalProxies; @@ -37,6 +38,7 @@ protected StateMachineRewriter( BoundStatement body, MethodSymbol method, SynthesizedContainer stateMachineType, + ArrayBuilder stateMachineStateDebugInfoBuilder, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics) @@ -47,10 +49,12 @@ protected StateMachineRewriter( Debug.Assert(compilationState != null); Debug.Assert(diagnostics != null); Debug.Assert(diagnostics.DiagnosticBag != null); + Debug.Assert(stateMachineStateDebugInfoBuilder.IsEmpty()); this.body = body; this.method = method; this.stateMachineType = stateMachineType; + this.stateMachineStateDebugInfoBuilder = stateMachineStateDebugInfoBuilder; this.slotAllocatorOpt = slotAllocatorOpt; this.synthesizedLocalOrdinals = new SynthesizedLocalOrdinalsDispenser(); this.diagnostics = diagnostics; @@ -433,7 +437,7 @@ protected SynthesizedImplementationMethod GenerateIteratorGetEnumerator(MethodSy makeIterator = F.If( // if (this.state == -2 && this.initialThreadId == Thread.CurrentThread.ManagedThreadId) condition: F.LogicalAnd( - F.IntEqual(F.Field(F.This(), stateField), F.Literal(StateMachineStates.FinishedStateMachine)), + F.IntEqual(F.Field(F.This(), stateField), F.Literal(StateMachineStates.FinishedState)), F.IntEqual(F.Field(F.This(), initialThreadIdField), managedThreadId)), thenClause: F.Block(thenBuilder.ToImmutableAndFree()), elseClauseOpt: makeIterator); diff --git a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineStates.cs b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineStates.cs index debc8437de81e..2f17bf33c8c4b 100644 --- a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineStates.cs +++ b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/StateMachineStates.cs @@ -2,17 +2,38 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - namespace Microsoft.CodeAnalysis.CSharp { internal static class StateMachineStates { - internal const int FinishedStateMachine = -2; - internal const int NotStartedStateMachine = -1; + internal const int FirstIteratorFinalizeState = -3; + + internal const int FinishedState = -2; + internal const int NotStartedOrRunningState = -1; internal const int FirstUnusedState = 0; - // used for async-iterators to distinguish initial state from running state (-1) so that DisposeAsync can throw in latter case - internal const int InitialAsyncIteratorStateMachine = -3; + /// + /// First state in async state machine that is used to resume the machine after await. + /// + internal const int FirstResumableAsyncState = 0; + + internal const int InitialIteratorState = 0; + + /// + /// First state in iterator state machine that is used to resume the machine after yield return. + /// Initial state is not used to resume state machine that yielded. + /// + internal const int FirstResumableIteratorState = InitialIteratorState + 1; + + /// + /// Used for async-iterators to distinguish initial state from so that DisposeAsync can throw in latter case. + /// + internal const int InitialAsyncIteratorState = -3; + + /// + /// First state in async iterator state machine that is used to resume the machine after yield return. + /// Initial state is not used to resume state machine that yielded. + /// + internal const int FirstResumableAsyncIteratorState = InitialAsyncIteratorState - 1; } } diff --git a/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs b/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs index 0e80a7df79155..520961b991669 100644 --- a/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs +++ b/src/Compilers/CSharp/Portable/Lowering/SyntheticBoundNodeFactory.cs @@ -983,7 +983,9 @@ public BoundStatement Switch(BoundExpression ex, ImmutableArray.GetInstance(); var statements = ArrayBuilder.GetInstance(); statements.Add(null!); // placeholder at statements[0] for the dispatch diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNames.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNames.cs index bb89a163099c0..cf9acb4bcd6e0 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNames.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/GeneratedNames.cs @@ -26,16 +26,14 @@ internal static string MakeBackingFieldName(string propertyName) return "<" + propertyName + ">k__BackingField"; } - internal static string MakeIteratorFinallyMethodName(int iteratorState) - { - // we can pick any name, but we will try to do - // <>m__Finally1 - // <>m__Finally2 - // <>m__Finally3 - // . . . - // that will roughly match native naming scheme and may also be easier when need to debug. + internal static string MakeIteratorFinallyMethodName(int finalizeState) + { + Debug.Assert(finalizeState < -2); + + // It is important that the name is only derived from the finalizeState, so that when + // editing method during EnC the Finally methods corresponding to matching states have matching names. Debug.Assert((char)GeneratedNameKind.IteratorFinallyMethod == 'm'); - return "<>m__Finally" + StringExtensions.GetNumeral(Math.Abs(iteratorState + 2)); + return "<>m__Finally" + StringExtensions.GetNumeral(-(finalizeState + 2)); } internal static string MakeStaticLambdaDisplayClassName(int methodOrdinal, int generation) diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxBindingUtilities.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxBindingUtilities.cs new file mode 100644 index 0000000000000..16800dd4ecb8e --- /dev/null +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxBindingUtilities.cs @@ -0,0 +1,27 @@ +// 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. + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.CodeAnalysis.CSharp.Syntax +{ + internal static class SyntaxBindingUtilities + { + public static bool BindsToResumableStateMachineState(SyntaxNode node) + => node.IsKind(SyntaxKind.YieldReturnStatement) || + node.IsKind(SyntaxKind.AwaitExpression) || + node is CommonForEachStatementSyntax { AwaitKeyword.RawKind: not 0 } + or VariableDeclaratorSyntax { Parent.Parent: UsingStatementSyntax { AwaitKeyword.RawKind: not 0 } or LocalDeclarationStatementSyntax { AwaitKeyword.RawKind: not 0 } } + or UsingStatementSyntax { Expression: not null, AwaitKeyword.RawKind: not 0 }; + + public static bool BindsToTryStatement(SyntaxNode node) + => node is VariableDeclaratorSyntax { Parent.Parent: UsingStatementSyntax { } or LocalDeclarationStatementSyntax { UsingKeyword.RawKind: not 0 } } + or UsingStatementSyntax { Expression: not null } + or CommonForEachStatementSyntax + or TryStatementSyntax + or LockStatementSyntax; + } +} diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncEHTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncEHTests.cs index 7d612c9e4f045..74d72686e20ea 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncEHTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncEHTests.cs @@ -973,6 +973,10 @@ public static void Main() + + + + diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncLocalsTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncLocalsTests.cs index ceecdf8225a84..d4349b1c7f0dd 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncLocalsTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncLocalsTests.cs @@ -364,6 +364,14 @@ public async Task M(IDisposable disposable) + + + + + + + + diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinuePdbTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinuePdbTests.cs index 76f7d9a55e97e..5b12f12413060 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinuePdbTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinuePdbTests.cs @@ -23,7 +23,7 @@ public class EditAndContinuePdbTests : EditAndContinueTestBase [MemberData(nameof(ExternalPdbFormats))] public void MethodExtents(DebugInformationFormat format) { - var source0 = MarkedSource(WithWindowsLineBreaks(@"#pragma checksum ""C:\Enc1.cs"" ""{ff1816ec-aa5e-4d10-87f7-6f4963833460}"" ""1111111111111111111111111111111111111111"" + var source0 = MarkedSource(@"#pragma checksum ""C:\Enc1.cs"" ""{ff1816ec-aa5e-4d10-87f7-6f4963833460}"" ""1111111111111111111111111111111111111111"" using System; public class C @@ -52,9 +52,9 @@ void G() }; } } -"), fileName: @"C:\Enc1.cs"); +", fileName: @"C:\Enc1.cs"); - var source1 = MarkedSource(WithWindowsLineBreaks(@"#pragma checksum ""C:\Enc1.cs"" ""{ff1816ec-aa5e-4d10-87f7-6f4963833460}"" ""2222222222222222222222222222222222222222"" + var source1 = MarkedSource(@"#pragma checksum ""C:\Enc1.cs"" ""{ff1816ec-aa5e-4d10-87f7-6f4963833460}"" ""2222222222222222222222222222222222222222"" using System; public class C @@ -83,9 +83,9 @@ void G() int E() => 1; } -"), fileName: @"C:\Enc1.cs"); +", fileName: @"C:\Enc1.cs"); - var source2 = MarkedSource(WithWindowsLineBreaks(@"#pragma checksum ""C:\Enc1.cs"" ""{ff1816ec-aa5e-4d10-87f7-6f4963833460}"" ""3333333333333333333333333333333333333333"" + var source2 = MarkedSource(@"#pragma checksum ""C:\Enc1.cs"" ""{ff1816ec-aa5e-4d10-87f7-6f4963833460}"" ""3333333333333333333333333333333333333333"" using System; public class C @@ -116,7 +116,7 @@ void G() int B() => 4; } -"), fileName: @"C:\Enc1.cs"); +", fileName: @"C:\Enc1.cs"); var compilation0 = CreateCompilation(source0.Tree, options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All), assemblyName: "EncMethodExtents"); var compilation1 = compilation0.WithSource(source1.Tree); diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs index 4db804c90174b..de960ec8f4dac 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs @@ -345,78 +345,78 @@ static IEnumerable F() var v0 = CompileAndVerify(compilation0); - using (var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData)) - { - var method0 = compilation0.GetMember("C.F"); - var method1 = compilation1.GetMember("C.F"); + using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + var method0 = compilation0.GetMember("C.F"); + var method1 = compilation1.GetMember("C.F"); - var generation0 = EmitBaseline.CreateInitialBaseline(md0, EmptyLocalsProvider); - var diff1 = compilation1.EmitDifference( - generation0, - ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1))); + var generation0 = EmitBaseline.CreateInitialBaseline(md0, EmptyLocalsProvider); + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1))); - using (var md1 = diff1.GetMetadata()) - { - CheckEncLogDefinitions(md1.Reader, - Row(2, TableIndex.StandAloneSig, EditAndContinueOperation.Default), - Row(3, TableIndex.StandAloneSig, EditAndContinueOperation.Default), - Row(5, TableIndex.TypeDef, EditAndContinueOperation.Default), - Row(1, TableIndex.PropertyMap, EditAndContinueOperation.Default), - Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddField), - Row(2, TableIndex.Field, EditAndContinueOperation.Default), - Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddField), - Row(3, TableIndex.Field, EditAndContinueOperation.Default), - Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddField), - Row(4, TableIndex.Field, EditAndContinueOperation.Default), - Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), - Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), - Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), - Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), - Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), - Row(7, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), - Row(8, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), - Row(9, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), - Row(10, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(1, TableIndex.PropertyMap, EditAndContinueOperation.AddProperty), - Row(1, TableIndex.Property, EditAndContinueOperation.Default), - Row(1, TableIndex.PropertyMap, EditAndContinueOperation.AddProperty), - Row(2, TableIndex.Property, EditAndContinueOperation.Default), - Row(3, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), - Row(1, TableIndex.Param, EditAndContinueOperation.Default), - Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(6, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(8, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(9, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(10, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(11, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(12, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(13, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(1, TableIndex.MethodSemantics, EditAndContinueOperation.Default), - Row(2, TableIndex.MethodSemantics, EditAndContinueOperation.Default), - Row(1, TableIndex.MethodImpl, EditAndContinueOperation.Default), - Row(2, TableIndex.MethodImpl, EditAndContinueOperation.Default), - Row(3, TableIndex.MethodImpl, EditAndContinueOperation.Default), - Row(4, TableIndex.MethodImpl, EditAndContinueOperation.Default), - Row(5, TableIndex.MethodImpl, EditAndContinueOperation.Default), - Row(6, TableIndex.MethodImpl, EditAndContinueOperation.Default), - Row(7, TableIndex.MethodImpl, EditAndContinueOperation.Default), - Row(2, TableIndex.NestedClass, EditAndContinueOperation.Default), - Row(1, TableIndex.InterfaceImpl, EditAndContinueOperation.Default), - Row(2, TableIndex.InterfaceImpl, EditAndContinueOperation.Default), - Row(3, TableIndex.InterfaceImpl, EditAndContinueOperation.Default), - Row(4, TableIndex.InterfaceImpl, EditAndContinueOperation.Default), - Row(5, TableIndex.InterfaceImpl, EditAndContinueOperation.Default)); - } - } + diff1.VerifySynthesizedMembers( + "C: {d__0#1}", + "C.d__0#1: {<>1__state, <>2__current, <>l__initialThreadId, System.IDisposable.Dispose, MoveNext, System.Collections.Generic.IEnumerator.get_Current, System.Collections.IEnumerator.Reset, System.Collections.IEnumerator.get_Current, System.Collections.Generic.IEnumerable.GetEnumerator, System.Collections.IEnumerable.GetEnumerator, System.Collections.Generic.IEnumerator.Current, System.Collections.IEnumerator.Current}"); + + using var md1 = diff1.GetMetadata(); + CheckEncLogDefinitions(md1.Reader, + Row(2, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(3, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(1, TableIndex.PropertyMap, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(2, TableIndex.Field, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(3, TableIndex.Field, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(4, TableIndex.Field, EditAndContinueOperation.Default), + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(7, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(8, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(9, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(10, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.PropertyMap, EditAndContinueOperation.AddProperty), + Row(1, TableIndex.Property, EditAndContinueOperation.Default), + Row(1, TableIndex.PropertyMap, EditAndContinueOperation.AddProperty), + Row(2, TableIndex.Property, EditAndContinueOperation.Default), + Row(3, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), + Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(6, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(8, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(9, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(10, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(11, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(12, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(13, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(1, TableIndex.MethodSemantics, EditAndContinueOperation.Default), + Row(2, TableIndex.MethodSemantics, EditAndContinueOperation.Default), + Row(1, TableIndex.MethodImpl, EditAndContinueOperation.Default), + Row(2, TableIndex.MethodImpl, EditAndContinueOperation.Default), + Row(3, TableIndex.MethodImpl, EditAndContinueOperation.Default), + Row(4, TableIndex.MethodImpl, EditAndContinueOperation.Default), + Row(5, TableIndex.MethodImpl, EditAndContinueOperation.Default), + Row(6, TableIndex.MethodImpl, EditAndContinueOperation.Default), + Row(7, TableIndex.MethodImpl, EditAndContinueOperation.Default), + Row(2, TableIndex.NestedClass, EditAndContinueOperation.Default), + Row(1, TableIndex.InterfaceImpl, EditAndContinueOperation.Default), + Row(2, TableIndex.InterfaceImpl, EditAndContinueOperation.Default), + Row(3, TableIndex.InterfaceImpl, EditAndContinueOperation.Default), + Row(4, TableIndex.InterfaceImpl, EditAndContinueOperation.Default), + Row(5, TableIndex.InterfaceImpl, EditAndContinueOperation.Default)); } [Fact] @@ -447,49 +447,49 @@ static async Task F() var v0 = CompileAndVerify(compilation0); - using (var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData)) - { - var method0 = compilation0.GetMember("C.F"); - var method1 = compilation1.GetMember("C.F"); + using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + var method0 = compilation0.GetMember("C.F"); + var method1 = compilation1.GetMember("C.F"); - var generation0 = EmitBaseline.CreateInitialBaseline(md0, EmptyLocalsProvider); - var diff1 = compilation1.EmitDifference( - generation0, - ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1))); + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1))); - using (var md1 = diff1.GetMetadata()) - { - CheckEncLogDefinitions(md1.Reader, - Row(2, TableIndex.StandAloneSig, EditAndContinueOperation.Default), - Row(3, TableIndex.StandAloneSig, EditAndContinueOperation.Default), - Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), - Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), - Row(1, TableIndex.Field, EditAndContinueOperation.Default), - Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), - Row(2, TableIndex.Field, EditAndContinueOperation.Default), - Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), - Row(3, TableIndex.Field, EditAndContinueOperation.Default), - Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), - Row(4, TableIndex.Field, EditAndContinueOperation.Default), - Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), - Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), - Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), - Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(5, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), - Row(1, TableIndex.Param, EditAndContinueOperation.Default), - Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(6, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(1, TableIndex.MethodImpl, EditAndContinueOperation.Default), - Row(2, TableIndex.MethodImpl, EditAndContinueOperation.Default), - Row(1, TableIndex.NestedClass, EditAndContinueOperation.Default), - Row(1, TableIndex.InterfaceImpl, EditAndContinueOperation.Default)); - } - } + diff1.VerifySynthesizedMembers( + "C.d__0#1: {<>1__state, <>t__builder, <>s__1, <>u__1, MoveNext, SetStateMachine}", + "C: {d__0#1}"); + + using var md1 = diff1.GetMetadata(); + CheckEncLogDefinitions(md1.Reader, + Row(2, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(3, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(2, TableIndex.Field, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(3, TableIndex.Field, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(4, TableIndex.Field, EditAndContinueOperation.Default), + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), + Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(6, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(1, TableIndex.MethodImpl, EditAndContinueOperation.Default), + Row(2, TableIndex.MethodImpl, EditAndContinueOperation.Default), + Row(1, TableIndex.NestedClass, EditAndContinueOperation.Default), + Row(1, TableIndex.InterfaceImpl, EditAndContinueOperation.Default)); } [Fact] @@ -571,28 +571,26 @@ static Task F() var v0 = CompileAndVerify(compilation0); - using (var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData)) - { - var method0 = compilation0.GetMember("C.F"); - var method1 = compilation1.GetMember("C.F"); - - var generation0 = EmitBaseline.CreateInitialBaseline(md0, EmptyLocalsProvider); - var diff1 = compilation1.EmitDifference( - generation0, - ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1))); + using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + var method0 = compilation0.GetMember("C.F"); + var method1 = compilation1.GetMember("C.F"); - using (var md1 = diff1.GetMetadata()) - { - CheckAttributes(md1.Reader, - new CustomAttributeRow(Handle(0, TableIndex.MethodDef), Handle(0, TableIndex.MemberRef)), // row id 0 == delete - new CustomAttributeRow(Handle(0, TableIndex.MethodDef), Handle(0, TableIndex.MemberRef))); // row id 0 == delete + var generation0 = EmitBaseline.CreateInitialBaseline(md0, EmptyLocalsProvider); + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1))); - CheckEncLogDefinitions(md1.Reader, - Row(3, TableIndex.StandAloneSig, EditAndContinueOperation.Default), - Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(1, TableIndex.CustomAttribute, EditAndContinueOperation.Default), // Delete AsyncStateMachineAttribute - Row(2, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); // Delete DebuggerStepThroughAttribute - } + using (var md1 = diff1.GetMetadata()) + { + CheckAttributes(md1.Reader, + new CustomAttributeRow(Handle(0, TableIndex.MethodDef), Handle(0, TableIndex.MemberRef)), // row id 0 == delete + new CustomAttributeRow(Handle(0, TableIndex.MethodDef), Handle(0, TableIndex.MemberRef))); // row id 0 == delete + + CheckEncLogDefinitions(md1.Reader, + Row(3, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.CustomAttribute, EditAndContinueOperation.Default), // Delete AsyncStateMachineAttribute + Row(2, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); // Delete DebuggerStepThroughAttribute } } @@ -644,53 +642,50 @@ static async Task F(int a) var v0 = CompileAndVerify(compilation0); - using (var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData)) - { - var methodShort0 = compilation0.GetMembers("C.F").Single(m => m.ToTestDisplayString() == "System.Threading.Tasks.Task C.F(System.Int16 a)"); - var methodShort1 = compilation1.GetMembers("C.F").Single(m => m.ToTestDisplayString() == "System.Threading.Tasks.Task C.F(System.Int16 a)"); + using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + var methodShort0 = compilation0.GetMembers("C.F").Single(m => m.ToTestDisplayString() == "System.Threading.Tasks.Task C.F(System.Int16 a)"); + var methodShort1 = compilation1.GetMembers("C.F").Single(m => m.ToTestDisplayString() == "System.Threading.Tasks.Task C.F(System.Int16 a)"); - var methodInt0 = compilation0.GetMembers("C.F").Single(m => m.ToTestDisplayString() == "System.Threading.Tasks.Task C.F(System.Int32 a)"); - var methodInt1 = compilation1.GetMembers("C.F").Single(m => m.ToTestDisplayString() == "System.Threading.Tasks.Task C.F(System.Int32 a)"); + var methodInt0 = compilation0.GetMembers("C.F").Single(m => m.ToTestDisplayString() == "System.Threading.Tasks.Task C.F(System.Int32 a)"); + var methodInt1 = compilation1.GetMembers("C.F").Single(m => m.ToTestDisplayString() == "System.Threading.Tasks.Task C.F(System.Int32 a)"); - var methodLong0 = compilation0.GetMembers("C.F").Single(m => m.ToTestDisplayString() == "System.Threading.Tasks.Task C.F(System.Int64 a)"); - var methodLong1 = compilation1.GetMembers("C.F").Single(m => m.ToTestDisplayString() == "System.Threading.Tasks.Task C.F(System.Int64 a)"); + var methodLong0 = compilation0.GetMembers("C.F").Single(m => m.ToTestDisplayString() == "System.Threading.Tasks.Task C.F(System.Int64 a)"); + var methodLong1 = compilation1.GetMembers("C.F").Single(m => m.ToTestDisplayString() == "System.Threading.Tasks.Task C.F(System.Int64 a)"); - var generation0 = EmitBaseline.CreateInitialBaseline(md0, EmptyLocalsProvider); - var diff1 = compilation1.EmitDifference( - generation0, - ImmutableArray.Create( - SemanticEdit.Create(SemanticEditKind.Update, methodShort0, methodShort1, preserveLocalVariables: true), - SemanticEdit.Create(SemanticEditKind.Update, methodInt0, methodInt1, preserveLocalVariables: true), - SemanticEdit.Create(SemanticEditKind.Update, methodLong0, methodLong1, preserveLocalVariables: true) - )); + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, methodShort0, methodShort1, preserveLocalVariables: true), + SemanticEdit.Create(SemanticEditKind.Update, methodInt0, methodInt1, preserveLocalVariables: true), + SemanticEdit.Create(SemanticEditKind.Update, methodLong0, methodLong1, preserveLocalVariables: true) + )); - using (var md1 = diff1.GetMetadata()) - { - // notice no TypeDefs, FieldDefs - CheckEncLogDefinitions(md1.Reader, - Row(7, TableIndex.StandAloneSig, EditAndContinueOperation.Default), - Row(8, TableIndex.StandAloneSig, EditAndContinueOperation.Default), - Row(9, TableIndex.StandAloneSig, EditAndContinueOperation.Default), - Row(10, TableIndex.StandAloneSig, EditAndContinueOperation.Default), - Row(11, TableIndex.StandAloneSig, EditAndContinueOperation.Default), - Row(12, TableIndex.StandAloneSig, EditAndContinueOperation.Default), - Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(9, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(12, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(1, TableIndex.Param, EditAndContinueOperation.Default), - Row(2, TableIndex.Param, EditAndContinueOperation.Default), - Row(3, TableIndex.Param, EditAndContinueOperation.Default), - Row(1, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(2, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(6, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(8, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(9, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); - } - } + using var md1 = diff1.GetMetadata(); + + // notice no TypeDefs, FieldDefs + CheckEncLogDefinitions(md1.Reader, + Row(7, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(8, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(9, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(10, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(11, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(12, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(9, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(12, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), + Row(2, TableIndex.Param, EditAndContinueOperation.Default), + Row(3, TableIndex.Param, EditAndContinueOperation.Default), + Row(1, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(2, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(6, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(8, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(9, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); } [Fact] @@ -1099,65 +1094,2207 @@ .locals init (int V_0, } [Fact] - public void UpdateIterator_UserDefinedVariables_NoChange() + public void UpdateAsync_Await_Add() { - var source0 = @" -using System.Collections.Generic; + var source0 = MarkedSource(@" +using System.Threading.Tasks; class C { - static IEnumerable F(int p) + static Task M1() => null; + static Task M2() => null; + static Task M3() => null; + static void End() {} + + static async Task F() { - int x = p; - yield return 1; + await M1(); + await M2(); + End(); } -}"; - var source1 = @" -using System.Collections.Generic; +}"); + var source1 = MarkedSource(@" +using System.Threading.Tasks; class C { - static IEnumerable F(int p) + static Task M1() => null; + static Task M2() => null; + static Task M3() => null; + static void End() {} + + static async Task F() { - int x = p; - yield return 2; + await M1(); + await M3(); + await M2(); + End(); } -}"; - var compilation0 = CreateCompilationWithMscorlib45(source0, options: ComSafeDebugDll); - var compilation1 = compilation0.WithSource(source1); +}"); + var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); var v0 = CompileAndVerify(compilation0); - var symReader = v0.CreateSymReader(); + v0.VerifyDiagnostics(); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); - using (var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData)) - { - var method0 = compilation0.GetMember("C.F"); - var method1 = compilation1.GetMember("C.F"); + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); - var generation0 = EmitBaseline.CreateInitialBaseline(md0, symReader.GetEncMethodDebugInfo); + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); - var diff1 = compilation1.EmitDifference( - generation0, - ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1, GetEquivalentNodesMap(method1, method0), preserveLocalVariables: true))); + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); - // Verify delta metadata contains expected rows. - using (var md1 = diff1.GetMetadata()) - { - // Verify that no new TypeDefs, FieldDefs or MethodDefs were added, - // 3 methods were updated: - // - the kick-off method (might be changed if the method previously wasn't an iterator) - // - Finally method - // - MoveNext method - CheckEncLogDefinitions(md1.Reader, - Row(3, TableIndex.StandAloneSig, EditAndContinueOperation.Default), - Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(1, TableIndex.Param, EditAndContinueOperation.Default), - Row(1, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); + v0.VerifyPdb("C.F", @" + + + + + + + + + + + + + + + + +"); + v0.VerifyPdb("C+d__4.MoveNext", @" + + + + + + + + + + + + + + + + + + + + + + + + +", options: PdbValidationOptions.ExcludeSequencePoints); - diff1.VerifyIL("C.d__0.System.Collections.IEnumerator.MoveNext", @" + v0.VerifyIL("C.d__4.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" +{ + // Code size 268 (0x10c) + .maxstack 3 + .locals init (int V_0, + System.Runtime.CompilerServices.TaskAwaiter V_1, + C.d__4 V_2, + System.Runtime.CompilerServices.TaskAwaiter V_3, + System.Exception V_4) + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__4.<>1__state"" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0012 + IL_000a: br.s IL_000c + IL_000c: ldloc.0 + IL_000d: ldc.i4.1 + IL_000e: beq.s IL_0014 + IL_0010: br.s IL_0019 + IL_0012: br.s IL_0055 + IL_0014: br IL_00b1 + + IL_0019: nop + IL_001a: call ""System.Threading.Tasks.Task C.M1()"" + IL_001f: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0024: stloc.1 + IL_0025: ldloca.s V_1 + IL_0027: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_002c: brtrue.s IL_0071 + + IL_002e: ldarg.0 + IL_002f: ldc.i4.0 + IL_0030: dup + IL_0031: stloc.0 + IL_0032: stfld ""int C.d__4.<>1__state"" + IL_0037: ldarg.0 + IL_0038: ldloc.1 + IL_0039: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_003e: ldarg.0 + IL_003f: stloc.2 + IL_0040: ldarg.0 + IL_0041: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_0046: ldloca.s V_1 + IL_0048: ldloca.s V_2 + IL_004a: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__4>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__4)"" + IL_004f: nop + IL_0050: leave IL_010b + + IL_0055: ldarg.0 + IL_0056: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_005b: stloc.1 + IL_005c: ldarg.0 + IL_005d: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_0062: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0068: ldarg.0 + IL_0069: ldc.i4.m1 + IL_006a: dup + IL_006b: stloc.0 + IL_006c: stfld ""int C.d__4.<>1__state"" + + IL_0071: ldloca.s V_1 + IL_0073: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0078: nop + IL_0079: call ""System.Threading.Tasks.Task C.M2()"" + IL_007e: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0083: stloc.3 + IL_0084: ldloca.s V_3 + IL_0086: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_008b: brtrue.s IL_00cd + + IL_008d: ldarg.0 + IL_008e: ldc.i4.1 + IL_008f: dup + IL_0090: stloc.0 + IL_0091: stfld ""int C.d__4.<>1__state"" + IL_0096: ldarg.0 + IL_0097: ldloc.3 + IL_0098: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_009d: ldarg.0 + IL_009e: stloc.2 + IL_009f: ldarg.0 + IL_00a0: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_00a5: ldloca.s V_3 + IL_00a7: ldloca.s V_2 + IL_00a9: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__4>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__4)"" + IL_00ae: nop + IL_00af: leave.s IL_010b + + IL_00b1: ldarg.0 + IL_00b2: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_00b7: stloc.3 + IL_00b8: ldarg.0 + IL_00b9: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_00be: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_00c4: ldarg.0 + IL_00c5: ldc.i4.m1 + IL_00c6: dup + IL_00c7: stloc.0 + IL_00c8: stfld ""int C.d__4.<>1__state"" + + IL_00cd: ldloca.s V_3 + IL_00cf: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_00d4: nop + IL_00d5: call ""void C.End()"" + IL_00da: nop + IL_00db: leave.s IL_00f7 + } + catch System.Exception + { + IL_00dd: stloc.s V_4 + IL_00df: ldarg.0 + IL_00e0: ldc.i4.s -2 + IL_00e2: stfld ""int C.d__4.<>1__state"" + IL_00e7: ldarg.0 + IL_00e8: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_00ed: ldloc.s V_4 + IL_00ef: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_00f4: nop + IL_00f5: leave.s IL_010b + } + IL_00f7: ldarg.0 + IL_00f8: ldc.i4.s -2 + IL_00fa: stfld ""int C.d__4.<>1__state"" + IL_00ff: ldarg.0 + IL_0100: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_0105: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_010a: nop + IL_010b: ret +} +"); + + diff1.VerifyIL("C.d__4.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" +{ + // Code size 380 (0x17c) + .maxstack 3 + .locals init (int V_0, + System.Runtime.CompilerServices.TaskAwaiter V_1, + C.d__4 V_2, + System.Runtime.CompilerServices.TaskAwaiter V_3, + System.Runtime.CompilerServices.TaskAwaiter V_4, + System.Exception V_5) + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__4.<>1__state"" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: switch ( + IL_001b, + IL_001d, + IL_0022) + IL_0019: br.s IL_0027 + IL_001b: br.s IL_0063 + IL_001d: br IL_0120 + IL_0022: br IL_00c2 + + IL_0027: nop + IL_0028: call ""System.Threading.Tasks.Task C.M1()"" + IL_002d: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0032: stloc.1 + IL_0033: ldloca.s V_1 + IL_0035: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_003a: brtrue.s IL_007f + + IL_003c: ldarg.0 + IL_003d: ldc.i4.0 + IL_003e: dup + IL_003f: stloc.0 + IL_0040: stfld ""int C.d__4.<>1__state"" + IL_0045: ldarg.0 + IL_0046: ldloc.1 + IL_0047: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_004c: ldarg.0 + IL_004d: stloc.2 + IL_004e: ldarg.0 + IL_004f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_0054: ldloca.s V_1 + IL_0056: ldloca.s V_2 + IL_0058: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__4>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__4)"" + IL_005d: nop + IL_005e: leave IL_017b + + IL_0063: ldarg.0 + IL_0064: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_0069: stloc.1 + IL_006a: ldarg.0 + IL_006b: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_0070: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0076: ldarg.0 + IL_0077: ldc.i4.m1 + IL_0078: dup + IL_0079: stloc.0 + IL_007a: stfld ""int C.d__4.<>1__state"" + + IL_007f: ldloca.s V_1 + IL_0081: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0086: nop + IL_0087: call ""System.Threading.Tasks.Task C.M3()"" + IL_008c: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0091: stloc.3 + IL_0092: ldloca.s V_3 + IL_0094: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_0099: brtrue.s IL_00de + + IL_009b: ldarg.0 + IL_009c: ldc.i4.2 + IL_009d: dup + IL_009e: stloc.0 + IL_009f: stfld ""int C.d__4.<>1__state"" + IL_00a4: ldarg.0 + IL_00a5: ldloc.3 + IL_00a6: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_00ab: ldarg.0 + IL_00ac: stloc.2 + IL_00ad: ldarg.0 + IL_00ae: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_00b3: ldloca.s V_3 + IL_00b5: ldloca.s V_2 + IL_00b7: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__4>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__4)"" + IL_00bc: nop + IL_00bd: leave IL_017b + + IL_00c2: ldarg.0 + IL_00c3: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_00c8: stloc.3 + IL_00c9: ldarg.0 + IL_00ca: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_00cf: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_00d5: ldarg.0 + IL_00d6: ldc.i4.m1 + IL_00d7: dup + IL_00d8: stloc.0 + IL_00d9: stfld ""int C.d__4.<>1__state"" + + IL_00de: ldloca.s V_3 + IL_00e0: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_00e5: nop + IL_00e6: call ""System.Threading.Tasks.Task C.M2()"" + IL_00eb: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_00f0: stloc.s V_4 + IL_00f2: ldloca.s V_4 + IL_00f4: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_00f9: brtrue.s IL_013d + + IL_00fb: ldarg.0 + IL_00fc: ldc.i4.1 + IL_00fd: dup + IL_00fe: stloc.0 + IL_00ff: stfld ""int C.d__4.<>1__state"" + IL_0104: ldarg.0 + IL_0105: ldloc.s V_4 + IL_0107: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_010c: ldarg.0 + IL_010d: stloc.2 + IL_010e: ldarg.0 + IL_010f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_0114: ldloca.s V_4 + IL_0116: ldloca.s V_2 + IL_0118: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__4>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__4)"" + IL_011d: nop + IL_011e: leave.s IL_017b + + IL_0120: ldarg.0 + IL_0121: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_0126: stloc.s V_4 + IL_0128: ldarg.0 + IL_0129: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_012e: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0134: ldarg.0 + IL_0135: ldc.i4.m1 + IL_0136: dup + IL_0137: stloc.0 + IL_0138: stfld ""int C.d__4.<>1__state"" + + IL_013d: ldloca.s V_4 + IL_013f: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0144: nop + IL_0145: call ""void C.End()"" + IL_014a: nop + IL_014b: leave.s IL_0167 + } + catch System.Exception + { + IL_014d: stloc.s V_5 + IL_014f: ldarg.0 + IL_0150: ldc.i4.s -2 + IL_0152: stfld ""int C.d__4.<>1__state"" + IL_0157: ldarg.0 + IL_0158: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_015d: ldloc.s V_5 + IL_015f: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_0164: nop + IL_0165: leave.s IL_017b + } + IL_0167: ldarg.0 + IL_0168: ldc.i4.s -2 + IL_016a: stfld ""int C.d__4.<>1__state"" + IL_016f: ldarg.0 + IL_0170: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_0175: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_017a: nop + IL_017b: ret +} +"); + } + + [Fact] + public void UpdateAsync_Await_Remove_RemoveAdd() + { + var source0 = MarkedSource(@" +using System.Threading.Tasks; + +class C +{ + static Task M1() => null; + static Task M2() => null; + static Task M3() => null; + static void End() {} + + static async Task F() + { + await M1(); + await M3(); + await M2(); + End(); + } +}"); + var source1 = MarkedSource(@" +using System.Threading.Tasks; + +class C +{ + static Task M1() => null; + static Task M2() => null; + static Task M3() => null; + static void End() {} + + static async Task F() + { + await M1(); + await M2(); + End(); + } +}"); + var source2 = MarkedSource(@" +using System.Threading.Tasks; + +class C +{ + static Task M1() => null; + static Task M2() => null; + static Task M3() => null; + static void End() {} + + static async Task F() + { + await M3(); + await M1(); + End(); + } +}"); + var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); + var compilation2 = compilation0.WithSource(source2.Tree); + + var v0 = CompileAndVerify(compilation0); + v0.VerifyDiagnostics(); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); + var f2 = compilation2.GetMember("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + var diff2 = compilation2.EmitDifference( + diff1.NextGeneration, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, f1, f2, GetSyntaxMapFromMarkers(source1, source2), preserveLocalVariables: true))); + + v0.VerifyPdb("C.F", @" + + + + + + + + + + + + + + + + + +"); + v0.VerifyPdb("C+d__4.MoveNext", @" + + + + + + + + + + + + + + + + + + + + + + + + + + +", options: PdbValidationOptions.ExcludeSequencePoints); + + v0.VerifyIL("C.d__4.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" +{ + // Code size 380 (0x17c) + .maxstack 3 + .locals init (int V_0, + System.Runtime.CompilerServices.TaskAwaiter V_1, + C.d__4 V_2, + System.Runtime.CompilerServices.TaskAwaiter V_3, + System.Runtime.CompilerServices.TaskAwaiter V_4, + System.Exception V_5) + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__4.<>1__state"" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: switch ( + IL_001b, + IL_001d, + IL_0022) + IL_0019: br.s IL_0027 + IL_001b: br.s IL_0063 + IL_001d: br IL_00c2 + IL_0022: br IL_0120 + + IL_0027: nop + IL_0028: call ""System.Threading.Tasks.Task C.M1()"" + IL_002d: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0032: stloc.1 + IL_0033: ldloca.s V_1 + IL_0035: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_003a: brtrue.s IL_007f + + IL_003c: ldarg.0 + IL_003d: ldc.i4.0 + IL_003e: dup + IL_003f: stloc.0 + IL_0040: stfld ""int C.d__4.<>1__state"" + IL_0045: ldarg.0 + IL_0046: ldloc.1 + IL_0047: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_004c: ldarg.0 + IL_004d: stloc.2 + IL_004e: ldarg.0 + IL_004f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_0054: ldloca.s V_1 + IL_0056: ldloca.s V_2 + IL_0058: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__4>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__4)"" + IL_005d: nop + IL_005e: leave IL_017b + + IL_0063: ldarg.0 + IL_0064: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_0069: stloc.1 + IL_006a: ldarg.0 + IL_006b: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_0070: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0076: ldarg.0 + IL_0077: ldc.i4.m1 + IL_0078: dup + IL_0079: stloc.0 + IL_007a: stfld ""int C.d__4.<>1__state"" + + IL_007f: ldloca.s V_1 + IL_0081: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0086: nop + IL_0087: call ""System.Threading.Tasks.Task C.M3()"" + IL_008c: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0091: stloc.3 + IL_0092: ldloca.s V_3 + IL_0094: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_0099: brtrue.s IL_00de + + IL_009b: ldarg.0 + IL_009c: ldc.i4.1 + IL_009d: dup + IL_009e: stloc.0 + IL_009f: stfld ""int C.d__4.<>1__state"" + IL_00a4: ldarg.0 + IL_00a5: ldloc.3 + IL_00a6: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_00ab: ldarg.0 + IL_00ac: stloc.2 + IL_00ad: ldarg.0 + IL_00ae: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_00b3: ldloca.s V_3 + IL_00b5: ldloca.s V_2 + IL_00b7: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__4>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__4)"" + IL_00bc: nop + IL_00bd: leave IL_017b + + IL_00c2: ldarg.0 + IL_00c3: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_00c8: stloc.3 + IL_00c9: ldarg.0 + IL_00ca: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_00cf: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_00d5: ldarg.0 + IL_00d6: ldc.i4.m1 + IL_00d7: dup + IL_00d8: stloc.0 + IL_00d9: stfld ""int C.d__4.<>1__state"" + + IL_00de: ldloca.s V_3 + IL_00e0: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_00e5: nop + IL_00e6: call ""System.Threading.Tasks.Task C.M2()"" + IL_00eb: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_00f0: stloc.s V_4 + IL_00f2: ldloca.s V_4 + IL_00f4: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_00f9: brtrue.s IL_013d + + IL_00fb: ldarg.0 + IL_00fc: ldc.i4.2 + IL_00fd: dup + IL_00fe: stloc.0 + IL_00ff: stfld ""int C.d__4.<>1__state"" + IL_0104: ldarg.0 + IL_0105: ldloc.s V_4 + IL_0107: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_010c: ldarg.0 + IL_010d: stloc.2 + IL_010e: ldarg.0 + IL_010f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_0114: ldloca.s V_4 + IL_0116: ldloca.s V_2 + IL_0118: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__4>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__4)"" + IL_011d: nop + IL_011e: leave.s IL_017b + + IL_0120: ldarg.0 + IL_0121: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_0126: stloc.s V_4 + IL_0128: ldarg.0 + IL_0129: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_012e: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0134: ldarg.0 + IL_0135: ldc.i4.m1 + IL_0136: dup + IL_0137: stloc.0 + IL_0138: stfld ""int C.d__4.<>1__state"" + + IL_013d: ldloca.s V_4 + IL_013f: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0144: nop + IL_0145: call ""void C.End()"" + IL_014a: nop + IL_014b: leave.s IL_0167 + } + catch System.Exception + { + IL_014d: stloc.s V_5 + IL_014f: ldarg.0 + IL_0150: ldc.i4.s -2 + IL_0152: stfld ""int C.d__4.<>1__state"" + IL_0157: ldarg.0 + IL_0158: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_015d: ldloc.s V_5 + IL_015f: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_0164: nop + IL_0165: leave.s IL_017b + } + IL_0167: ldarg.0 + IL_0168: ldc.i4.s -2 + IL_016a: stfld ""int C.d__4.<>1__state"" + IL_016f: ldarg.0 + IL_0170: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_0175: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_017a: nop + IL_017b: ret +} +"); + + diff1.VerifyIL("C.d__4.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" +{ + // Code size 283 (0x11b) + .maxstack 3 + .locals init (int V_0, + System.Runtime.CompilerServices.TaskAwaiter V_1, + C.d__4 V_2, + System.Runtime.CompilerServices.TaskAwaiter V_3, + System.Exception V_4) + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__4.<>1__state"" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0012 + IL_000a: br.s IL_000c + IL_000c: ldloc.0 + IL_000d: ldc.i4.2 + IL_000e: beq.s IL_0014 + IL_0010: br.s IL_0019 + IL_0012: br.s IL_0064 + IL_0014: br IL_00c0 + IL_0019: ldloc.0 + IL_001a: ldc.i4.0 + IL_001b: blt.s IL_0028 + IL_001d: ldstr """ + CodeAnalysisResources.EncCannotResumeSuspendedAsyncMethod + @""" + IL_0022: newobj ""System.InvalidOperationException..ctor(string)"" + IL_0027: throw + + IL_0028: nop + IL_0029: call ""System.Threading.Tasks.Task C.M1()"" + IL_002e: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0033: stloc.1 + IL_0034: ldloca.s V_1 + IL_0036: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_003b: brtrue.s IL_0080 + + IL_003d: ldarg.0 + IL_003e: ldc.i4.0 + IL_003f: dup + IL_0040: stloc.0 + IL_0041: stfld ""int C.d__4.<>1__state"" + IL_0046: ldarg.0 + IL_0047: ldloc.1 + IL_0048: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_004d: ldarg.0 + IL_004e: stloc.2 + IL_004f: ldarg.0 + IL_0050: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_0055: ldloca.s V_1 + IL_0057: ldloca.s V_2 + IL_0059: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__4>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__4)"" + IL_005e: nop + IL_005f: leave IL_011a + + IL_0064: ldarg.0 + IL_0065: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_006a: stloc.1 + IL_006b: ldarg.0 + IL_006c: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_0071: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0077: ldarg.0 + IL_0078: ldc.i4.m1 + IL_0079: dup + IL_007a: stloc.0 + IL_007b: stfld ""int C.d__4.<>1__state"" + IL_0080: ldloca.s V_1 + IL_0082: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0087: nop + IL_0088: call ""System.Threading.Tasks.Task C.M2()"" + IL_008d: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0092: stloc.3 + IL_0093: ldloca.s V_3 + IL_0095: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_009a: brtrue.s IL_00dc + + IL_009c: ldarg.0 + IL_009d: ldc.i4.2 + IL_009e: dup + IL_009f: stloc.0 + IL_00a0: stfld ""int C.d__4.<>1__state"" + IL_00a5: ldarg.0 + IL_00a6: ldloc.3 + IL_00a7: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_00ac: ldarg.0 + IL_00ad: stloc.2 + IL_00ae: ldarg.0 + IL_00af: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_00b4: ldloca.s V_3 + IL_00b6: ldloca.s V_2 + IL_00b8: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__4>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__4)"" + IL_00bd: nop + IL_00be: leave.s IL_011a + + IL_00c0: ldarg.0 + IL_00c1: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_00c6: stloc.3 + IL_00c7: ldarg.0 + IL_00c8: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_00cd: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_00d3: ldarg.0 + IL_00d4: ldc.i4.m1 + IL_00d5: dup + IL_00d6: stloc.0 + IL_00d7: stfld ""int C.d__4.<>1__state"" + + IL_00dc: ldloca.s V_3 + IL_00de: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_00e3: nop + IL_00e4: call ""void C.End()"" + IL_00e9: nop + IL_00ea: leave.s IL_0106 + } + catch System.Exception + { + IL_00ec: stloc.s V_4 + IL_00ee: ldarg.0 + IL_00ef: ldc.i4.s -2 + IL_00f1: stfld ""int C.d__4.<>1__state"" + IL_00f6: ldarg.0 + IL_00f7: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_00fc: ldloc.s V_4 + IL_00fe: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_0103: nop + IL_0104: leave.s IL_011a + } + IL_0106: ldarg.0 + IL_0107: ldc.i4.s -2 + IL_0109: stfld ""int C.d__4.<>1__state"" + IL_010e: ldarg.0 + IL_010f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_0114: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_0119: nop + IL_011a: ret +} +"); + // note that CDI is not emitted to the delta since we already have the information captured in changed symbols: + diff1.VerifyPdb(Enumerable.Range(1, 20).Select(MetadataTokens.MethodDefinitionHandle), @" + + + + + + + + + + + + + + + + +"); + diff2.VerifyIL("C.d__4.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" +{ + // Code size 283 (0x11b) + .maxstack 3 + .locals init (int V_0, + System.Runtime.CompilerServices.TaskAwaiter V_1, + C.d__4 V_2, + System.Runtime.CompilerServices.TaskAwaiter V_3, + System.Exception V_4) + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__4.<>1__state"" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0012 + IL_000a: br.s IL_000c + IL_000c: ldloc.0 + IL_000d: ldc.i4.3 + IL_000e: beq.s IL_0017 + IL_0010: br.s IL_0019 + IL_0012: br IL_00c0 + IL_0017: br.s IL_0064 + IL_0019: ldloc.0 + IL_001a: ldc.i4.0 + IL_001b: blt.s IL_0028 + IL_001d: ldstr """ + CodeAnalysisResources.EncCannotResumeSuspendedAsyncMethod + @""" + IL_0022: newobj ""System.InvalidOperationException..ctor(string)"" + IL_0027: throw + + IL_0028: nop + IL_0029: call ""System.Threading.Tasks.Task C.M3()"" + IL_002e: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0033: stloc.1 + IL_0034: ldloca.s V_1 + IL_0036: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_003b: brtrue.s IL_0080 + + IL_003d: ldarg.0 + IL_003e: ldc.i4.3 + IL_003f: dup + IL_0040: stloc.0 + IL_0041: stfld ""int C.d__4.<>1__state"" + IL_0046: ldarg.0 + IL_0047: ldloc.1 + IL_0048: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_004d: ldarg.0 + IL_004e: stloc.2 + IL_004f: ldarg.0 + IL_0050: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_0055: ldloca.s V_1 + IL_0057: ldloca.s V_2 + IL_0059: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__4>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__4)"" + IL_005e: nop + IL_005f: leave IL_011a + + IL_0064: ldarg.0 + IL_0065: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_006a: stloc.1 + IL_006b: ldarg.0 + IL_006c: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_0071: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0077: ldarg.0 + IL_0078: ldc.i4.m1 + IL_0079: dup + IL_007a: stloc.0 + IL_007b: stfld ""int C.d__4.<>1__state"" + + IL_0080: ldloca.s V_1 + IL_0082: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0087: nop + IL_0088: call ""System.Threading.Tasks.Task C.M1()"" + IL_008d: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0092: stloc.3 + IL_0093: ldloca.s V_3 + IL_0095: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_009a: brtrue.s IL_00dc + + IL_009c: ldarg.0 + IL_009d: ldc.i4.0 + IL_009e: dup + IL_009f: stloc.0 + IL_00a0: stfld ""int C.d__4.<>1__state"" + IL_00a5: ldarg.0 + IL_00a6: ldloc.3 + IL_00a7: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_00ac: ldarg.0 + IL_00ad: stloc.2 + IL_00ae: ldarg.0 + IL_00af: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_00b4: ldloca.s V_3 + IL_00b6: ldloca.s V_2 + IL_00b8: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__4>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__4)"" + IL_00bd: nop + IL_00be: leave.s IL_011a + + IL_00c0: ldarg.0 + IL_00c1: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_00c6: stloc.3 + IL_00c7: ldarg.0 + IL_00c8: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_00cd: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_00d3: ldarg.0 + IL_00d4: ldc.i4.m1 + IL_00d5: dup + IL_00d6: stloc.0 + IL_00d7: stfld ""int C.d__4.<>1__state"" + + IL_00dc: ldloca.s V_3 + IL_00de: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_00e3: nop + IL_00e4: call ""void C.End()"" + IL_00e9: nop + IL_00ea: leave.s IL_0106 + } + catch System.Exception + { + IL_00ec: stloc.s V_4 + IL_00ee: ldarg.0 + IL_00ef: ldc.i4.s -2 + IL_00f1: stfld ""int C.d__4.<>1__state"" + IL_00f6: ldarg.0 + IL_00f7: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_00fc: ldloc.s V_4 + IL_00fe: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_0103: nop + IL_0104: leave.s IL_011a + } + IL_0106: ldarg.0 + IL_0107: ldc.i4.s -2 + IL_0109: stfld ""int C.d__4.<>1__state"" + IL_010e: ldarg.0 + IL_010f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_0114: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_0119: nop + IL_011a: ret +} +"); + } + + [Fact] + public void UpdateAsync_Await_Remove_FirstAndLast() + { + var source0 = MarkedSource(@" +using System.Threading.Tasks; + +class C +{ + static Task M1() => null; + static Task M2() => null; + static Task M3() => null; + static void End() {} + + static async Task F() + { + await M1(); + await M2(); + await M3(); + End(); + } +}"); + var source1 = MarkedSource(@" +using System.Threading.Tasks; + +class C +{ + static Task M1() => null; + static Task M2() => null; + static Task M3() => null; + static void End() {} + + static async Task F() + { + await M2(); + End(); + } +}"); + var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); + + var v0 = CompileAndVerify(compilation0); + v0.VerifyDiagnostics(); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + diff1.VerifyIL("C.d__4.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" +{ + // Code size 176 (0xb0) + .maxstack 3 + .locals init (int V_0, + System.Runtime.CompilerServices.TaskAwaiter V_1, + C.d__4 V_2, + System.Exception V_3) + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__4.<>1__state"" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: ldc.i4.1 + IL_0009: beq.s IL_000d + IL_000b: br.s IL_000f + IL_000d: br.s IL_0057 + IL_000f: ldloc.0 + IL_0010: ldc.i4.0 + IL_0011: blt.s IL_001e + IL_0013: ldstr """ + CodeAnalysisResources.EncCannotResumeSuspendedAsyncMethod + @""" + IL_0018: newobj ""System.InvalidOperationException..ctor(string)"" + IL_001d: throw + + IL_001e: nop + IL_001f: call ""System.Threading.Tasks.Task C.M2()"" + IL_0024: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0029: stloc.1 + IL_002a: ldloca.s V_1 + IL_002c: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_0031: brtrue.s IL_0073 + + IL_0033: ldarg.0 + IL_0034: ldc.i4.1 + IL_0035: dup + IL_0036: stloc.0 + IL_0037: stfld ""int C.d__4.<>1__state"" + IL_003c: ldarg.0 + IL_003d: ldloc.1 + IL_003e: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_0043: ldarg.0 + IL_0044: stloc.2 + IL_0045: ldarg.0 + IL_0046: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_004b: ldloca.s V_1 + IL_004d: ldloca.s V_2 + IL_004f: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__4>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__4)"" + IL_0054: nop + IL_0055: leave.s IL_00af + + IL_0057: ldarg.0 + IL_0058: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_005d: stloc.1 + IL_005e: ldarg.0 + IL_005f: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__4.<>u__1"" + IL_0064: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_006a: ldarg.0 + IL_006b: ldc.i4.m1 + IL_006c: dup + IL_006d: stloc.0 + IL_006e: stfld ""int C.d__4.<>1__state"" + + IL_0073: ldloca.s V_1 + IL_0075: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_007a: nop + IL_007b: call ""void C.End()"" + IL_0080: nop + IL_0081: leave.s IL_009b + } + catch System.Exception + { + IL_0083: stloc.3 + IL_0084: ldarg.0 + IL_0085: ldc.i4.s -2 + IL_0087: stfld ""int C.d__4.<>1__state"" + IL_008c: ldarg.0 + IL_008d: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_0092: ldloc.3 + IL_0093: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_0098: nop + IL_0099: leave.s IL_00af + } + IL_009b: ldarg.0 + IL_009c: ldc.i4.s -2 + IL_009e: stfld ""int C.d__4.<>1__state"" + IL_00a3: ldarg.0 + IL_00a4: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__4.<>t__builder"" + IL_00a9: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_00ae: nop + IL_00af: ret +} +"); + } + + [Fact] + public void UpdateAsync_Await_Remove_TryBlock() + { + var source0 = MarkedSource(@" +using System.Threading.Tasks; + +class C +{ + static void Start() {} + static Task M1() => null; + static Task M2() => null; + static Task M3() => null; + static Task M4() => null; + static Task M5() => null; + static void End() {} + + static async Task F() + { + Start(); + await M1(); + try + { + await M2(); + await M3(); + } + catch + { + await M4(); + await M5(); + } + End(); + } +}"); + var source1 = MarkedSource(@" +using System.Threading.Tasks; + +class C +{ + static void Start() {} + static Task M1() => null; + static Task M2() => null; + static Task M3() => null; + static Task M4() => null; + static Task M5() => null; + static void End() {} + + static async Task F() + { + Start(); + try + { + await M2(); + } + catch + { + await M4(); + } + End(); + } +}"); + var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); + + var v0 = CompileAndVerify(compilation0); + v0.VerifyDiagnostics(); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + v0.VerifyIL("C.d__7.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" +{ + // Code size 671 (0x29f) + .maxstack 3 + .locals init (int V_0, + System.Runtime.CompilerServices.TaskAwaiter V_1, + C.d__7 V_2, + System.Runtime.CompilerServices.TaskAwaiter V_3, + System.Runtime.CompilerServices.TaskAwaiter V_4, + object V_5, + int V_6, + System.Runtime.CompilerServices.TaskAwaiter V_7, + System.Runtime.CompilerServices.TaskAwaiter V_8, + System.Exception V_9) + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__7.<>1__state"" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: switch ( + IL_0023, + IL_0025, + IL_0025, + IL_0027, + IL_002c) + IL_0021: br.s IL_0031 + IL_0023: br.s IL_0073 + IL_0025: br.s IL_009e + IL_0027: br IL_01da + IL_002c: br IL_0239 + + IL_0031: nop + IL_0032: call ""void C.Start()"" + IL_0037: nop + IL_0038: call ""System.Threading.Tasks.Task C.M1()"" + IL_003d: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0042: stloc.1 + IL_0043: ldloca.s V_1 + IL_0045: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_004a: brtrue.s IL_008f + + IL_004c: ldarg.0 + IL_004d: ldc.i4.0 + IL_004e: dup + IL_004f: stloc.0 + IL_0050: stfld ""int C.d__7.<>1__state"" + IL_0055: ldarg.0 + IL_0056: ldloc.1 + IL_0057: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" + IL_005c: ldarg.0 + IL_005d: stloc.2 + IL_005e: ldarg.0 + IL_005f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__7.<>t__builder"" + IL_0064: ldloca.s V_1 + IL_0066: ldloca.s V_2 + IL_0068: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__7>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__7)"" + IL_006d: nop + IL_006e: leave IL_029e + + IL_0073: ldarg.0 + IL_0074: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" + IL_0079: stloc.1 + IL_007a: ldarg.0 + IL_007b: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" + IL_0080: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0086: ldarg.0 + IL_0087: ldc.i4.m1 + IL_0088: dup + IL_0089: stloc.0 + IL_008a: stfld ""int C.d__7.<>1__state"" + + IL_008f: ldloca.s V_1 + IL_0091: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0096: nop + IL_0097: ldarg.0 + IL_0098: ldc.i4.0 + IL_0099: stfld ""int C.d__7.<>s__2"" + + IL_009e: nop + .try + { + IL_009f: ldloc.0 + IL_00a0: ldc.i4.1 + IL_00a1: beq.s IL_00ab + IL_00a3: br.s IL_00a5 + IL_00a5: ldloc.0 + IL_00a6: ldc.i4.2 + IL_00a7: beq.s IL_00ad + IL_00a9: br.s IL_00b2 + IL_00ab: br.s IL_00ee + IL_00ad: br IL_014f + + IL_00b2: nop + IL_00b3: call ""System.Threading.Tasks.Task C.M2()"" + IL_00b8: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_00bd: stloc.3 + IL_00be: ldloca.s V_3 + IL_00c0: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_00c5: brtrue.s IL_010a + + IL_00c7: ldarg.0 + IL_00c8: ldc.i4.1 + IL_00c9: dup + IL_00ca: stloc.0 + IL_00cb: stfld ""int C.d__7.<>1__state"" + IL_00d0: ldarg.0 + IL_00d1: ldloc.3 + IL_00d2: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" + IL_00d7: ldarg.0 + IL_00d8: stloc.2 + IL_00d9: ldarg.0 + IL_00da: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__7.<>t__builder"" + IL_00df: ldloca.s V_3 + IL_00e1: ldloca.s V_2 + IL_00e3: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__7>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__7)"" + IL_00e8: nop + IL_00e9: leave IL_029e + + IL_00ee: ldarg.0 + IL_00ef: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" + IL_00f4: stloc.3 + IL_00f5: ldarg.0 + IL_00f6: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" + IL_00fb: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0101: ldarg.0 + IL_0102: ldc.i4.m1 + IL_0103: dup + IL_0104: stloc.0 + IL_0105: stfld ""int C.d__7.<>1__state"" + + IL_010a: ldloca.s V_3 + IL_010c: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0111: nop + IL_0112: call ""System.Threading.Tasks.Task C.M3()"" + IL_0117: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_011c: stloc.s V_4 + IL_011e: ldloca.s V_4 + IL_0120: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_0125: brtrue.s IL_016c + + IL_0127: ldarg.0 + IL_0128: ldc.i4.2 + IL_0129: dup + IL_012a: stloc.0 + IL_012b: stfld ""int C.d__7.<>1__state"" + IL_0130: ldarg.0 + IL_0131: ldloc.s V_4 + IL_0133: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" + IL_0138: ldarg.0 + IL_0139: stloc.2 + IL_013a: ldarg.0 + IL_013b: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__7.<>t__builder"" + IL_0140: ldloca.s V_4 + IL_0142: ldloca.s V_2 + IL_0144: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__7>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__7)"" + IL_0149: nop + IL_014a: leave IL_029e + + IL_014f: ldarg.0 + IL_0150: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" + IL_0155: stloc.s V_4 + IL_0157: ldarg.0 + IL_0158: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" + IL_015d: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0163: ldarg.0 + IL_0164: ldc.i4.m1 + IL_0165: dup + IL_0166: stloc.0 + IL_0167: stfld ""int C.d__7.<>1__state"" + + IL_016c: ldloca.s V_4 + IL_016e: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0173: nop + IL_0174: nop + IL_0175: leave.s IL_018a + } + catch object + { + IL_0177: stloc.s V_5 + IL_0179: ldarg.0 + IL_017a: ldloc.s V_5 + IL_017c: stfld ""object C.d__7.<>s__1"" + IL_0181: ldarg.0 + IL_0182: ldc.i4.1 + IL_0183: stfld ""int C.d__7.<>s__2"" + IL_0188: leave.s IL_018a + } + IL_018a: ldarg.0 + IL_018b: ldfld ""int C.d__7.<>s__2"" + IL_0190: stloc.s V_6 + IL_0192: ldloc.s V_6 + IL_0194: ldc.i4.1 + IL_0195: beq.s IL_019c + IL_0197: br IL_0261 + + IL_019c: nop + IL_019d: call ""System.Threading.Tasks.Task C.M4()"" + IL_01a2: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_01a7: stloc.s V_7 + IL_01a9: ldloca.s V_7 + IL_01ab: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_01b0: brtrue.s IL_01f7 + + IL_01b2: ldarg.0 + IL_01b3: ldc.i4.3 + IL_01b4: dup + IL_01b5: stloc.0 + IL_01b6: stfld ""int C.d__7.<>1__state"" + IL_01bb: ldarg.0 + IL_01bc: ldloc.s V_7 + IL_01be: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" + IL_01c3: ldarg.0 + IL_01c4: stloc.2 + IL_01c5: ldarg.0 + IL_01c6: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__7.<>t__builder"" + IL_01cb: ldloca.s V_7 + IL_01cd: ldloca.s V_2 + IL_01cf: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__7>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__7)"" + IL_01d4: nop + IL_01d5: leave IL_029e + + IL_01da: ldarg.0 + IL_01db: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" + IL_01e0: stloc.s V_7 + IL_01e2: ldarg.0 + IL_01e3: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" + IL_01e8: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_01ee: ldarg.0 + IL_01ef: ldc.i4.m1 + IL_01f0: dup + IL_01f1: stloc.0 + IL_01f2: stfld ""int C.d__7.<>1__state"" + + IL_01f7: ldloca.s V_7 + IL_01f9: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_01fe: nop + IL_01ff: call ""System.Threading.Tasks.Task C.M5()"" + IL_0204: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0209: stloc.s V_8 + IL_020b: ldloca.s V_8 + IL_020d: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_0212: brtrue.s IL_0256 + + IL_0214: ldarg.0 + IL_0215: ldc.i4.4 + IL_0216: dup + IL_0217: stloc.0 + IL_0218: stfld ""int C.d__7.<>1__state"" + IL_021d: ldarg.0 + IL_021e: ldloc.s V_8 + IL_0220: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" + IL_0225: ldarg.0 + IL_0226: stloc.2 + IL_0227: ldarg.0 + IL_0228: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__7.<>t__builder"" + IL_022d: ldloca.s V_8 + IL_022f: ldloca.s V_2 + IL_0231: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__7>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__7)"" + IL_0236: nop + IL_0237: leave.s IL_029e + + IL_0239: ldarg.0 + IL_023a: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" + IL_023f: stloc.s V_8 + IL_0241: ldarg.0 + IL_0242: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" + IL_0247: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_024d: ldarg.0 + IL_024e: ldc.i4.m1 + IL_024f: dup + IL_0250: stloc.0 + IL_0251: stfld ""int C.d__7.<>1__state"" + + IL_0256: ldloca.s V_8 + IL_0258: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_025d: nop + IL_025e: nop + IL_025f: br.s IL_0261 + + IL_0261: ldarg.0 + IL_0262: ldnull + IL_0263: stfld ""object C.d__7.<>s__1"" + IL_0268: call ""void C.End()"" + IL_026d: nop + IL_026e: leave.s IL_028a + } + catch System.Exception + { + IL_0270: stloc.s V_9 + IL_0272: ldarg.0 + IL_0273: ldc.i4.s -2 + IL_0275: stfld ""int C.d__7.<>1__state"" + IL_027a: ldarg.0 + IL_027b: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__7.<>t__builder"" + IL_0280: ldloc.s V_9 + IL_0282: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_0287: nop + IL_0288: leave.s IL_029e + } + IL_028a: ldarg.0 + IL_028b: ldc.i4.s -2 + IL_028d: stfld ""int C.d__7.<>1__state"" + IL_0292: ldarg.0 + IL_0293: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__7.<>t__builder"" + IL_0298: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_029d: nop + IL_029e: ret +} +"); + + diff1.VerifyIL("C.d__7.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" +{ + // Code size 356 (0x164) + .maxstack 3 + .locals init (int V_0, + System.Runtime.CompilerServices.TaskAwaiter V_1, + C.d__7 V_2, + object V_3, + int V_4, + System.Runtime.CompilerServices.TaskAwaiter V_5, + System.Exception V_6) + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__7.<>1__state"" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: ldc.i4.1 + IL_0009: beq.s IL_0013 + IL_000b: br.s IL_000d + IL_000d: ldloc.0 + IL_000e: ldc.i4.2 + IL_000f: beq.s IL_0015 + IL_0011: br.s IL_001a + IL_0013: br.s IL_0037 + IL_0015: br IL_00fe + IL_001a: ldloc.0 + IL_001b: ldc.i4.0 + IL_001c: blt.s IL_0029 + IL_001e: ldstr """ + CodeAnalysisResources.EncCannotResumeSuspendedAsyncMethod + @""" + IL_0023: newobj ""System.InvalidOperationException..ctor(string)"" + IL_0028: throw + + IL_0029: nop + IL_002a: call ""void C.Start()"" + IL_002f: nop + IL_0030: ldarg.0 + IL_0031: ldc.i4.0 + IL_0032: stfld ""int C.d__7.<>s__4"" + + IL_0037: nop + .try + { + IL_0038: ldloc.0 + IL_0039: ldc.i4.1 + IL_003a: beq.s IL_003e + IL_003c: br.s IL_0040 + IL_003e: br.s IL_007c + + IL_0040: nop + IL_0041: call ""System.Threading.Tasks.Task C.M2()"" + IL_0046: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_004b: stloc.1 + IL_004c: ldloca.s V_1 + IL_004e: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_0053: brtrue.s IL_0098 + + IL_0055: ldarg.0 + IL_0056: ldc.i4.1 + IL_0057: dup + IL_0058: stloc.0 + IL_0059: stfld ""int C.d__7.<>1__state"" + IL_005e: ldarg.0 + IL_005f: ldloc.1 + IL_0060: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" + IL_0065: ldarg.0 + IL_0066: stloc.2 + IL_0067: ldarg.0 + IL_0068: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__7.<>t__builder"" + IL_006d: ldloca.s V_1 + IL_006f: ldloca.s V_2 + IL_0071: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__7>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__7)"" + IL_0076: nop + IL_0077: leave IL_0163 + + IL_007c: ldarg.0 + IL_007d: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" + IL_0082: stloc.1 + IL_0083: ldarg.0 + IL_0084: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" + IL_0089: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_008f: ldarg.0 + IL_0090: ldc.i4.m1 + IL_0091: dup + IL_0092: stloc.0 + IL_0093: stfld ""int C.d__7.<>1__state"" + IL_0098: ldloca.s V_1 + IL_009a: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_009f: nop + IL_00a0: nop + IL_00a1: leave.s IL_00b4 + } + catch object + { + IL_00a3: stloc.3 + IL_00a4: ldarg.0 + IL_00a5: ldloc.3 + IL_00a6: stfld ""object C.d__7.<>s__3"" + IL_00ab: ldarg.0 + IL_00ac: ldc.i4.1 + IL_00ad: stfld ""int C.d__7.<>s__4"" + IL_00b2: leave.s IL_00b4 + } + IL_00b4: ldarg.0 + IL_00b5: ldfld ""int C.d__7.<>s__4"" + IL_00ba: stloc.s V_4 + IL_00bc: ldloc.s V_4 + IL_00be: ldc.i4.1 + IL_00bf: beq.s IL_00c3 + IL_00c1: br.s IL_0126 + + IL_00c3: nop + IL_00c4: call ""System.Threading.Tasks.Task C.M4()"" + IL_00c9: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_00ce: stloc.s V_5 + IL_00d0: ldloca.s V_5 + IL_00d2: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_00d7: brtrue.s IL_011b + + IL_00d9: ldarg.0 + IL_00da: ldc.i4.2 + IL_00db: dup + IL_00dc: stloc.0 + IL_00dd: stfld ""int C.d__7.<>1__state"" + IL_00e2: ldarg.0 + IL_00e3: ldloc.s V_5 + IL_00e5: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" + IL_00ea: ldarg.0 + IL_00eb: stloc.2 + IL_00ec: ldarg.0 + IL_00ed: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__7.<>t__builder"" + IL_00f2: ldloca.s V_5 + IL_00f4: ldloca.s V_2 + IL_00f6: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__7>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__7)"" + IL_00fb: nop + IL_00fc: leave.s IL_0163 + + IL_00fe: ldarg.0 + IL_00ff: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" + IL_0104: stloc.s V_5 + IL_0106: ldarg.0 + IL_0107: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__7.<>u__1"" + IL_010c: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0112: ldarg.0 + IL_0113: ldc.i4.m1 + IL_0114: dup + IL_0115: stloc.0 + IL_0116: stfld ""int C.d__7.<>1__state"" + + IL_011b: ldloca.s V_5 + IL_011d: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0122: nop + IL_0123: nop + IL_0124: br.s IL_0126 + + IL_0126: ldarg.0 + IL_0127: ldnull + IL_0128: stfld ""object C.d__7.<>s__3"" + IL_012d: call ""void C.End()"" + IL_0132: nop + IL_0133: leave.s IL_014f + } + catch System.Exception + { + IL_0135: stloc.s V_6 + IL_0137: ldarg.0 + IL_0138: ldc.i4.s -2 + IL_013a: stfld ""int C.d__7.<>1__state"" + IL_013f: ldarg.0 + IL_0140: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__7.<>t__builder"" + IL_0145: ldloc.s V_6 + IL_0147: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_014c: nop + IL_014d: leave.s IL_0163 + } + IL_014f: ldarg.0 + IL_0150: ldc.i4.s -2 + IL_0152: stfld ""int C.d__7.<>1__state"" + IL_0157: ldarg.0 + IL_0158: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__7.<>t__builder"" + IL_015d: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_0162: nop + IL_0163: ret +} +"); + } + + [Fact] + public void UpdateAsync_AwaitDeclarationMappedToNonAwait() + { + var source0 = MarkedSource(@" +using System; +using System.Threading.Tasks; + +class C +{ + static async Task F() + { + await Task.CompletedTask; + IAsyncDisposable x = G(), y = G(); + } + + static IAsyncDisposable G() => null; +}"); + var source1 = MarkedSource(@" +using System; +using System.Threading.Tasks; + +class C +{ + static async Task F() + { + await Task.CompletedTask; + await using IAsyncDisposable x = G(), y = G(); + } + + static IAsyncDisposable G() => null; +}"); + var asyncStreamsTree = Parse(AsyncStreamsTypes); + + var compilation0 = CreateCompilationWithTasksExtensions(new[] { source0.Tree, asyncStreamsTree }, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(new[] { source1.Tree, asyncStreamsTree }); + + var v0 = CompileAndVerify(compilation0); + v0.VerifyDiagnostics(); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + // Note that the CDI contains local variable declaration mapping to facilitate local variable slot allocation, + // but these are not included in the state machine map since the V0 version of the local declaration statement does not have "await" keyword. + // Therefore, the V1 version will not be able ot match the local declaration statements to their previous versions when emitting + // state machine states and create new states for them as expected. + v0.VerifyPdb("C.F", @" + + + + + + + + + + + + + + + + + + +"); + + // note preserved hoisted variables x, y: + + v0.VerifySynthesizedFields("C.d__0", + "int <>1__state", + "System.Runtime.CompilerServices.AsyncTaskMethodBuilder <>t__builder", + "System.IAsyncDisposable 5__1", + "System.IAsyncDisposable 5__2", + "System.Runtime.CompilerServices.TaskAwaiter <>u__1"); + + diff1.VerifySynthesizedFields("C.d__0", + "<>1__state: int", + "<>t__builder: System.Runtime.CompilerServices.AsyncTaskMethodBuilder", + "5__1: System.IAsyncDisposable", + "5__2: System.IAsyncDisposable", + "<>s__3: object", + "<>s__4: int", + "<>s__5: object", + "<>s__6: int", + "<>u__1: System.Runtime.CompilerServices.TaskAwaiter", + "<>u__2: System.Runtime.CompilerServices.ValueTaskAwaiter"); + + diff1.VerifyIL("C.d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" +{ + // Code size 678 (0x2a6) + .maxstack 3 + .locals init (int V_0, + System.Runtime.CompilerServices.TaskAwaiter V_1, + C.d__0 V_2, + object V_3, + System.Runtime.CompilerServices.ValueTaskAwaiter V_4, + System.Threading.Tasks.ValueTask V_5, + System.Exception V_6, + int V_7, + System.Runtime.CompilerServices.ValueTaskAwaiter V_8) + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__0.<>1__state"" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: switch ( + IL_001b, + IL_001d, + IL_001f) + IL_0019: br.s IL_0024 + IL_001b: br.s IL_0060 + IL_001d: br.s IL_009d + IL_001f: br IL_01e9 + IL_0024: nop + IL_0025: call ""System.Threading.Tasks.Task System.Threading.Tasks.Task.CompletedTask.get"" + IL_002a: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_002f: stloc.1 + IL_0030: ldloca.s V_1 + IL_0032: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_0037: brtrue.s IL_007c + IL_0039: ldarg.0 + IL_003a: ldc.i4.0 + IL_003b: dup + IL_003c: stloc.0 + IL_003d: stfld ""int C.d__0.<>1__state"" + IL_0042: ldarg.0 + IL_0043: ldloc.1 + IL_0044: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_0049: ldarg.0 + IL_004a: stloc.2 + IL_004b: ldarg.0 + IL_004c: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__0.<>t__builder"" + IL_0051: ldloca.s V_1 + IL_0053: ldloca.s V_2 + IL_0055: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__0)"" + IL_005a: nop + IL_005b: leave IL_02a5 + IL_0060: ldarg.0 + IL_0061: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_0066: stloc.1 + IL_0067: ldarg.0 + IL_0068: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_006d: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0073: ldarg.0 + IL_0074: ldc.i4.m1 + IL_0075: dup + IL_0076: stloc.0 + IL_0077: stfld ""int C.d__0.<>1__state"" + IL_007c: ldloca.s V_1 + IL_007e: call ""void System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0083: nop + IL_0084: ldarg.0 + IL_0085: call ""System.IAsyncDisposable C.G()"" + IL_008a: stfld ""System.IAsyncDisposable C.d__0.5__1"" + IL_008f: ldarg.0 + IL_0090: ldnull + IL_0091: stfld ""object C.d__0.<>s__3"" + IL_0096: ldarg.0 + IL_0097: ldc.i4.0 + IL_0098: stfld ""int C.d__0.<>s__4"" + IL_009d: nop + .try + { + IL_009e: ldloc.0 + IL_009f: ldc.i4.1 + IL_00a0: beq.s IL_00a4 + IL_00a2: br.s IL_00a6 + IL_00a4: br.s IL_0123 + IL_00a6: ldarg.0 + IL_00a7: call ""System.IAsyncDisposable C.G()"" + IL_00ac: stfld ""System.IAsyncDisposable C.d__0.5__2"" + IL_00b1: ldarg.0 + IL_00b2: ldnull + IL_00b3: stfld ""object C.d__0.<>s__5"" + IL_00b8: ldarg.0 + IL_00b9: ldc.i4.0 + IL_00ba: stfld ""int C.d__0.<>s__6"" + .try + { + IL_00bf: br.s IL_00c1 + IL_00c1: ldarg.0 + IL_00c2: ldc.i4.1 + IL_00c3: stfld ""int C.d__0.<>s__6"" + IL_00c8: leave.s IL_00d4 + } + catch object + { + IL_00ca: stloc.3 + IL_00cb: ldarg.0 + IL_00cc: ldloc.3 + IL_00cd: stfld ""object C.d__0.<>s__5"" + IL_00d2: leave.s IL_00d4 + } + IL_00d4: ldarg.0 + IL_00d5: ldfld ""System.IAsyncDisposable C.d__0.5__2"" + IL_00da: brfalse.s IL_0148 + IL_00dc: ldarg.0 + IL_00dd: ldfld ""System.IAsyncDisposable C.d__0.5__2"" + IL_00e2: callvirt ""System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"" + IL_00e7: stloc.s V_5 + IL_00e9: ldloca.s V_5 + IL_00eb: call ""System.Runtime.CompilerServices.ValueTaskAwaiter System.Threading.Tasks.ValueTask.GetAwaiter()"" + IL_00f0: stloc.s V_4 + IL_00f2: ldloca.s V_4 + IL_00f4: call ""bool System.Runtime.CompilerServices.ValueTaskAwaiter.IsCompleted.get"" + IL_00f9: brtrue.s IL_0140 + IL_00fb: ldarg.0 + IL_00fc: ldc.i4.1 + IL_00fd: dup + IL_00fe: stloc.0 + IL_00ff: stfld ""int C.d__0.<>1__state"" + IL_0104: ldarg.0 + IL_0105: ldloc.s V_4 + IL_0107: stfld ""System.Runtime.CompilerServices.ValueTaskAwaiter C.d__0.<>u__2"" + IL_010c: ldarg.0 + IL_010d: stloc.2 + IL_010e: ldarg.0 + IL_010f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__0.<>t__builder"" + IL_0114: ldloca.s V_4 + IL_0116: ldloca.s V_2 + IL_0118: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__0>(ref System.Runtime.CompilerServices.ValueTaskAwaiter, ref C.d__0)"" + IL_011d: nop + IL_011e: leave IL_02a5 + IL_0123: ldarg.0 + IL_0124: ldfld ""System.Runtime.CompilerServices.ValueTaskAwaiter C.d__0.<>u__2"" + IL_0129: stloc.s V_4 + IL_012b: ldarg.0 + IL_012c: ldflda ""System.Runtime.CompilerServices.ValueTaskAwaiter C.d__0.<>u__2"" + IL_0131: initobj ""System.Runtime.CompilerServices.ValueTaskAwaiter"" + IL_0137: ldarg.0 + IL_0138: ldc.i4.m1 + IL_0139: dup + IL_013a: stloc.0 + IL_013b: stfld ""int C.d__0.<>1__state"" + IL_0140: ldloca.s V_4 + IL_0142: call ""void System.Runtime.CompilerServices.ValueTaskAwaiter.GetResult()"" + IL_0147: nop + IL_0148: ldarg.0 + IL_0149: ldfld ""object C.d__0.<>s__5"" + IL_014e: stloc.3 + IL_014f: ldloc.3 + IL_0150: brfalse.s IL_016d + IL_0152: ldloc.3 + IL_0153: isinst ""System.Exception"" + IL_0158: stloc.s V_6 + IL_015a: ldloc.s V_6 + IL_015c: brtrue.s IL_0160 + IL_015e: ldloc.3 + IL_015f: throw + IL_0160: ldloc.s V_6 + IL_0162: call ""System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"" + IL_0167: callvirt ""void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"" + IL_016c: nop + IL_016d: ldarg.0 + IL_016e: ldfld ""int C.d__0.<>s__6"" + IL_0173: stloc.s V_7 + IL_0175: ldloc.s V_7 + IL_0177: ldc.i4.1 + IL_0178: beq.s IL_017c + IL_017a: br.s IL_017e + IL_017c: br.s IL_0187 + IL_017e: ldarg.0 + IL_017f: ldnull + IL_0180: stfld ""object C.d__0.<>s__5"" + IL_0185: leave.s IL_019a + IL_0187: ldarg.0 + IL_0188: ldc.i4.1 + IL_0189: stfld ""int C.d__0.<>s__4"" + IL_018e: leave.s IL_019a + } + catch object + { + IL_0190: stloc.3 + IL_0191: ldarg.0 + IL_0192: ldloc.3 + IL_0193: stfld ""object C.d__0.<>s__3"" + IL_0198: leave.s IL_019a + } + IL_019a: ldarg.0 + IL_019b: ldfld ""System.IAsyncDisposable C.d__0.5__1"" + IL_01a0: brfalse.s IL_020e + IL_01a2: ldarg.0 + IL_01a3: ldfld ""System.IAsyncDisposable C.d__0.5__1"" + IL_01a8: callvirt ""System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync()"" + IL_01ad: stloc.s V_5 + IL_01af: ldloca.s V_5 + IL_01b1: call ""System.Runtime.CompilerServices.ValueTaskAwaiter System.Threading.Tasks.ValueTask.GetAwaiter()"" + IL_01b6: stloc.s V_8 + IL_01b8: ldloca.s V_8 + IL_01ba: call ""bool System.Runtime.CompilerServices.ValueTaskAwaiter.IsCompleted.get"" + IL_01bf: brtrue.s IL_0206 + IL_01c1: ldarg.0 + IL_01c2: ldc.i4.2 + IL_01c3: dup + IL_01c4: stloc.0 + IL_01c5: stfld ""int C.d__0.<>1__state"" + IL_01ca: ldarg.0 + IL_01cb: ldloc.s V_8 + IL_01cd: stfld ""System.Runtime.CompilerServices.ValueTaskAwaiter C.d__0.<>u__2"" + IL_01d2: ldarg.0 + IL_01d3: stloc.2 + IL_01d4: ldarg.0 + IL_01d5: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__0.<>t__builder"" + IL_01da: ldloca.s V_8 + IL_01dc: ldloca.s V_2 + IL_01de: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedd__0>(ref System.Runtime.CompilerServices.ValueTaskAwaiter, ref C.d__0)"" + IL_01e3: nop + IL_01e4: leave IL_02a5 + IL_01e9: ldarg.0 + IL_01ea: ldfld ""System.Runtime.CompilerServices.ValueTaskAwaiter C.d__0.<>u__2"" + IL_01ef: stloc.s V_8 + IL_01f1: ldarg.0 + IL_01f2: ldflda ""System.Runtime.CompilerServices.ValueTaskAwaiter C.d__0.<>u__2"" + IL_01f7: initobj ""System.Runtime.CompilerServices.ValueTaskAwaiter"" + IL_01fd: ldarg.0 + IL_01fe: ldc.i4.m1 + IL_01ff: dup + IL_0200: stloc.0 + IL_0201: stfld ""int C.d__0.<>1__state"" + IL_0206: ldloca.s V_8 + IL_0208: call ""void System.Runtime.CompilerServices.ValueTaskAwaiter.GetResult()"" + IL_020d: nop + IL_020e: ldarg.0 + IL_020f: ldfld ""object C.d__0.<>s__3"" + IL_0214: stloc.3 + IL_0215: ldloc.3 + IL_0216: brfalse.s IL_0233 + IL_0218: ldloc.3 + IL_0219: isinst ""System.Exception"" + IL_021e: stloc.s V_6 + IL_0220: ldloc.s V_6 + IL_0222: brtrue.s IL_0226 + IL_0224: ldloc.3 + IL_0225: throw + IL_0226: ldloc.s V_6 + IL_0228: call ""System.Runtime.ExceptionServices.ExceptionDispatchInfo System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(System.Exception)"" + IL_022d: callvirt ""void System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()"" + IL_0232: nop + IL_0233: ldarg.0 + IL_0234: ldfld ""int C.d__0.<>s__4"" + IL_0239: stloc.s V_7 + IL_023b: ldloc.s V_7 + IL_023d: ldc.i4.1 + IL_023e: beq.s IL_0242 + IL_0240: br.s IL_0244 + IL_0242: leave.s IL_0283 + IL_0244: ldarg.0 + IL_0245: ldnull + IL_0246: stfld ""object C.d__0.<>s__3"" + IL_024b: ldarg.0 + IL_024c: ldnull + IL_024d: stfld ""System.IAsyncDisposable C.d__0.5__1"" + IL_0252: ldarg.0 + IL_0253: ldnull + IL_0254: stfld ""System.IAsyncDisposable C.d__0.5__2"" + IL_0259: leave.s IL_0283 + } + catch System.Exception + { + IL_025b: stloc.s V_6 + IL_025d: ldarg.0 + IL_025e: ldc.i4.s -2 + IL_0260: stfld ""int C.d__0.<>1__state"" + IL_0265: ldarg.0 + IL_0266: ldnull + IL_0267: stfld ""System.IAsyncDisposable C.d__0.5__1"" + IL_026c: ldarg.0 + IL_026d: ldnull + IL_026e: stfld ""System.IAsyncDisposable C.d__0.5__2"" + IL_0273: ldarg.0 + IL_0274: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__0.<>t__builder"" + IL_0279: ldloc.s V_6 + IL_027b: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException(System.Exception)"" + IL_0280: nop + IL_0281: leave.s IL_02a5 + } + IL_0283: ldarg.0 + IL_0284: ldc.i4.s -2 + IL_0286: stfld ""int C.d__0.<>1__state"" + IL_028b: ldarg.0 + IL_028c: ldnull + IL_028d: stfld ""System.IAsyncDisposable C.d__0.5__1"" + IL_0292: ldarg.0 + IL_0293: ldnull + IL_0294: stfld ""System.IAsyncDisposable C.d__0.5__2"" + IL_0299: ldarg.0 + IL_029a: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder C.d__0.<>t__builder"" + IL_029f: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetResult()"" + IL_02a4: nop + IL_02a5: ret +}"); + } + + [Fact] + public void UpdateIterator_UserDefinedVariables_NoChange() + { + var source0 = MarkedSource(@" +using System.Collections.Generic; + +class C +{ + static IEnumerable F(int p) + { + int x = p; + yield return 1; + } +}"); + var source1 = MarkedSource(@" +using System.Collections.Generic; + +class C +{ + static IEnumerable F(int p) + { + int x = p; + yield return 2; + } +}"); + var compilation0 = CreateCompilationWithMscorlib45(source0.Tree, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); + + var v0 = CompileAndVerify(compilation0); + var symReader = v0.CreateSymReader(); + + using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + var method0 = compilation0.GetMember("C.F"); + var method1 = compilation1.GetMember("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, symReader.GetEncMethodDebugInfo); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + // Verify delta metadata contains expected rows. + using var md1 = diff1.GetMetadata(); + + // Verify that no new TypeDefs, FieldDefs or MethodDefs were added, + // 3 methods were updated: + // - the kick-off method (might be changed if the method previously wasn't an iterator) + // - Finally method + // - MoveNext method + CheckEncLogDefinitions(md1.Reader, + Row(3, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), + Row(1, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); + + diff1.VerifyIL("C.d__0.System.Collections.IEnumerator.MoveNext", @" { // Code size 69 (0x45) .maxstack 2 @@ -1166,648 +3303,2806 @@ .locals init (int V_0) IL_0001: ldfld ""int C.d__0.<>1__state"" IL_0006: stloc.0 IL_0007: ldloc.0 - IL_0008: brfalse.s IL_0012 - IL_000a: br.s IL_000c - IL_000c: ldloc.0 - IL_000d: ldc.i4.1 - IL_000e: beq.s IL_0014 - IL_0010: br.s IL_0016 - IL_0012: br.s IL_0018 - IL_0014: br.s IL_003c - IL_0016: ldc.i4.0 - IL_0017: ret - IL_0018: ldarg.0 - IL_0019: ldc.i4.m1 - IL_001a: stfld ""int C.d__0.<>1__state"" - IL_001f: nop - IL_0020: ldarg.0 - IL_0021: ldarg.0 - IL_0022: ldfld ""int C.d__0.p"" - IL_0027: stfld ""int C.d__0.5__1"" - IL_002c: ldarg.0 - IL_002d: ldc.i4.2 - IL_002e: stfld ""int C.d__0.<>2__current"" - IL_0033: ldarg.0 - IL_0034: ldc.i4.1 - IL_0035: stfld ""int C.d__0.<>1__state"" - IL_003a: ldc.i4.1 - IL_003b: ret - IL_003c: ldarg.0 - IL_003d: ldc.i4.m1 - IL_003e: stfld ""int C.d__0.<>1__state"" - IL_0043: ldc.i4.0 - IL_0044: ret + IL_0008: brfalse.s IL_0012 + IL_000a: br.s IL_000c + IL_000c: ldloc.0 + IL_000d: ldc.i4.1 + IL_000e: beq.s IL_0014 + IL_0010: br.s IL_0016 + IL_0012: br.s IL_0018 + IL_0014: br.s IL_003c + IL_0016: ldc.i4.0 + IL_0017: ret + IL_0018: ldarg.0 + IL_0019: ldc.i4.m1 + IL_001a: stfld ""int C.d__0.<>1__state"" + IL_001f: nop + IL_0020: ldarg.0 + IL_0021: ldarg.0 + IL_0022: ldfld ""int C.d__0.p"" + IL_0027: stfld ""int C.d__0.5__1"" + IL_002c: ldarg.0 + IL_002d: ldc.i4.2 + IL_002e: stfld ""int C.d__0.<>2__current"" + IL_0033: ldarg.0 + IL_0034: ldc.i4.1 + IL_0035: stfld ""int C.d__0.<>1__state"" + IL_003a: ldc.i4.1 + IL_003b: ret + IL_003c: ldarg.0 + IL_003d: ldc.i4.m1 + IL_003e: stfld ""int C.d__0.<>1__state"" + IL_0043: ldc.i4.0 + IL_0044: ret +}"); + } + + [Fact] + public void UpdateIterator_UserDefinedVariables_AddVariable() + { + var source0 = MarkedSource(@" +using System; +using System.Collections.Generic; + +class C +{ + static IEnumerable F(int p) + { + int x = p; + yield return x; + } +}"); + var source1 = MarkedSource(@" +using System; +using System.Collections.Generic; + +class C +{ + static IEnumerable F(int p) + { + int y = 1234; + int x = p; + yield return y; + Console.WriteLine(x); + } +}"); + var compilation0 = CreateCompilationWithMscorlib45(source0.Tree, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); + + var v0 = CompileAndVerify(compilation0); + var symReader = v0.CreateSymReader(); + + using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + var method0 = compilation0.GetMember("C.F"); + var method1 = compilation1.GetMember("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, symReader.GetEncMethodDebugInfo); + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + // Verify delta metadata contains expected rows. + using var md1 = diff1.GetMetadata(); + + // 1 field def added & 3 methods updated + CheckEncLogDefinitions(md1.Reader, + Row(3, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(7, TableIndex.Field, EditAndContinueOperation.Default), + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), + Row(1, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); + + diff1.VerifyIL("C.d__0.System.Collections.IEnumerator.MoveNext", @" +{ + // Code size 97 (0x61) + .maxstack 2 + .locals init (int V_0) + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__0.<>1__state"" + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0012 + IL_000a: br.s IL_000c + IL_000c: ldloc.0 + IL_000d: ldc.i4.1 + IL_000e: beq.s IL_0014 + IL_0010: br.s IL_0016 + IL_0012: br.s IL_0018 + IL_0014: br.s IL_004c + IL_0016: ldc.i4.0 + IL_0017: ret + IL_0018: ldarg.0 + IL_0019: ldc.i4.m1 + IL_001a: stfld ""int C.d__0.<>1__state"" + IL_001f: nop + IL_0020: ldarg.0 + IL_0021: ldc.i4 0x4d2 + IL_0026: stfld ""int C.d__0.5__2"" + IL_002b: ldarg.0 + IL_002c: ldarg.0 + IL_002d: ldfld ""int C.d__0.p"" + IL_0032: stfld ""int C.d__0.5__1"" + IL_0037: ldarg.0 + IL_0038: ldarg.0 + IL_0039: ldfld ""int C.d__0.5__2"" + IL_003e: stfld ""int C.d__0.<>2__current"" + IL_0043: ldarg.0 + IL_0044: ldc.i4.1 + IL_0045: stfld ""int C.d__0.<>1__state"" + IL_004a: ldc.i4.1 + IL_004b: ret + IL_004c: ldarg.0 + IL_004d: ldc.i4.m1 + IL_004e: stfld ""int C.d__0.<>1__state"" + IL_0053: ldarg.0 + IL_0054: ldfld ""int C.d__0.5__1"" + IL_0059: call ""void System.Console.WriteLine(int)"" + IL_005e: nop + IL_005f: ldc.i4.0 + IL_0060: ret +}"); + } + + [Fact] + public void UpdateIterator_UserDefinedVariables_AddAndRemoveVariable() + { + var source0 = MarkedSource(@" +using System; +using System.Collections.Generic; + +class C +{ + static IEnumerable F(int p) + { + int x = p; + yield return x; + } +}"); + var source1 = MarkedSource(@" +using System; +using System.Collections.Generic; + +class C +{ + static IEnumerable F(int p) + { + int y = 1234; + yield return y; + Console.WriteLine(p); + } +}"); + var compilation0 = CreateCompilationWithMscorlib45(source0.Tree, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); + + var v0 = CompileAndVerify(compilation0); + var symReader = v0.CreateSymReader(); + + using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + var method0 = compilation0.GetMember("C.F"); + var method1 = compilation1.GetMember("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, symReader.GetEncMethodDebugInfo); + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + // Verify delta metadata contains expected rows. + using var md1 = diff1.GetMetadata(); + + // 1 field def added & 3 methods updated + CheckEncLogDefinitions(md1.Reader, + Row(3, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(7, TableIndex.Field, EditAndContinueOperation.Default), + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), + Row(1, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); + + diff1.VerifyIL("C.d__0.System.Collections.IEnumerator.MoveNext", @" +{ + // Code size 85 (0x55) + .maxstack 2 + .locals init (int V_0) + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__0.<>1__state"" + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0012 + IL_000a: br.s IL_000c + IL_000c: ldloc.0 + IL_000d: ldc.i4.1 + IL_000e: beq.s IL_0014 + IL_0010: br.s IL_0016 + IL_0012: br.s IL_0018 + IL_0014: br.s IL_0040 + IL_0016: ldc.i4.0 + IL_0017: ret + IL_0018: ldarg.0 + IL_0019: ldc.i4.m1 + IL_001a: stfld ""int C.d__0.<>1__state"" + IL_001f: nop + IL_0020: ldarg.0 + IL_0021: ldc.i4 0x4d2 + IL_0026: stfld ""int C.d__0.5__2"" + IL_002b: ldarg.0 + IL_002c: ldarg.0 + IL_002d: ldfld ""int C.d__0.5__2"" + IL_0032: stfld ""int C.d__0.<>2__current"" + IL_0037: ldarg.0 + IL_0038: ldc.i4.1 + IL_0039: stfld ""int C.d__0.<>1__state"" + IL_003e: ldc.i4.1 + IL_003f: ret + IL_0040: ldarg.0 + IL_0041: ldc.i4.m1 + IL_0042: stfld ""int C.d__0.<>1__state"" + IL_0047: ldarg.0 + IL_0048: ldfld ""int C.d__0.p"" + IL_004d: call ""void System.Console.WriteLine(int)"" + IL_0052: nop + IL_0053: ldc.i4.0 + IL_0054: ret +}"); + } + + [Fact] + public void UpdateIterator_UserDefinedVariables_ChangeVariableType() + { + var source0 = MarkedSource(@" +using System; +using System.Collections.Generic; + +class C +{ + static IEnumerable F() + { + var x = 1; + yield return 1; + Console.WriteLine(x); + } +}"); + var source1 = MarkedSource(@" +using System; +using System.Collections.Generic; + +class C +{ + static IEnumerable F() + { + var x = 1.0; + yield return 2; + Console.WriteLine(x); + } +}"); + var compilation0 = CreateCompilationWithMscorlib45(source0.Tree, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); + + var v0 = CompileAndVerify(compilation0); + var symReader = v0.CreateSymReader(); + + using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + var method0 = compilation0.GetMember("C.F"); + var method1 = compilation1.GetMember("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, symReader.GetEncMethodDebugInfo); + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + // Verify delta metadata contains expected rows. + using var md1 = diff1.GetMetadata(); + + // 1 field def added & 3 methods updated + CheckEncLogDefinitions(md1.Reader, + Row(3, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(5, TableIndex.Field, EditAndContinueOperation.Default), + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); + + diff1.VerifyIL("C.d__0.System.Collections.IEnumerator.MoveNext", @" +{ + // Code size 84 (0x54) + .maxstack 2 + .locals init (int V_0) + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__0.<>1__state"" + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0012 + IL_000a: br.s IL_000c + IL_000c: ldloc.0 + IL_000d: ldc.i4.1 + IL_000e: beq.s IL_0014 + IL_0010: br.s IL_0016 + IL_0012: br.s IL_0018 + IL_0014: br.s IL_003f + IL_0016: ldc.i4.0 + IL_0017: ret + IL_0018: ldarg.0 + IL_0019: ldc.i4.m1 + IL_001a: stfld ""int C.d__0.<>1__state"" + IL_001f: nop + IL_0020: ldarg.0 + IL_0021: ldc.r8 1 + IL_002a: stfld ""double C.d__0.5__2"" + IL_002f: ldarg.0 + IL_0030: ldc.i4.2 + IL_0031: stfld ""int C.d__0.<>2__current"" + IL_0036: ldarg.0 + IL_0037: ldc.i4.1 + IL_0038: stfld ""int C.d__0.<>1__state"" + IL_003d: ldc.i4.1 + IL_003e: ret + IL_003f: ldarg.0 + IL_0040: ldc.i4.m1 + IL_0041: stfld ""int C.d__0.<>1__state"" + IL_0046: ldarg.0 + IL_0047: ldfld ""double C.d__0.5__2"" + IL_004c: call ""void System.Console.WriteLine(double)"" + IL_0051: nop + IL_0052: ldc.i4.0 + IL_0053: ret +}"); + } + + [Fact] + public void UpdateIterator_SynthesizedVariables_ChangeVariableType() + { + var source0 = MarkedSource(@" +using System; +using System.Collections.Generic; + +class C +{ + static IEnumerable F() + { + foreach (object item in new[] { 1 }) { yield return 1; } + } +}"); + var source1 = MarkedSource(@" +using System; +using System.Collections.Generic; + +class C +{ + static IEnumerable F() + { + foreach (object item in new[] { 1.0 }) { yield return 1; } + } +}"); + // Rude edit but the compiler should handle it. + + var compilation0 = CreateCompilationWithMscorlib45(source0.Tree, options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + var compilation1 = compilation0.WithSource(source1.Tree); + + var v0 = CompileAndVerify(compilation0, symbolValidator: module => + { + Assert.Equal(new[] + { + "<>1__state: int", + "<>2__current: int", + "<>l__initialThreadId: int", + "<>s__1: int[]", + "<>s__2: int", + "5__3: object" + }, module.GetFieldNamesAndTypes("C.d__0")); + }); + + var symReader = v0.CreateSymReader(); + + using var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + var method0 = compilation0.GetMember("C.F"); + var method1 = compilation1.GetMember("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, symReader.GetEncMethodDebugInfo); + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + // Verify delta metadata contains expected rows. + using var md1 = diff1.GetMetadata(); + + // 1 field def added & 3 methods updated + CheckEncLogDefinitions(md1.Reader, + Row(3, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(7, TableIndex.Field, EditAndContinueOperation.Default), + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(1, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); + + diff1.VerifyIL("C.d__0.System.Collections.IEnumerator.MoveNext", @" +{ + // Code size 161 (0xa1) + .maxstack 5 + .locals init (int V_0) + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__0.<>1__state"" + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: brfalse.s IL_0012 + IL_000a: br.s IL_000c + IL_000c: ldloc.0 + IL_000d: ldc.i4.1 + IL_000e: beq.s IL_0014 + IL_0010: br.s IL_0016 + IL_0012: br.s IL_0018 + IL_0014: br.s IL_006b + IL_0016: ldc.i4.0 + IL_0017: ret + IL_0018: ldarg.0 + IL_0019: ldc.i4.m1 + IL_001a: stfld ""int C.d__0.<>1__state"" + IL_001f: nop + IL_0020: nop + IL_0021: ldarg.0 + IL_0022: ldc.i4.1 + IL_0023: newarr ""double"" + IL_0028: dup + IL_0029: ldc.i4.0 + IL_002a: ldc.r8 1 + IL_0033: stelem.r8 + IL_0034: stfld ""double[] C.d__0.<>s__4"" + IL_0039: ldarg.0 + IL_003a: ldc.i4.0 + IL_003b: stfld ""int C.d__0.<>s__2"" + IL_0040: br.s IL_0088 + IL_0042: ldarg.0 + IL_0043: ldarg.0 + IL_0044: ldfld ""double[] C.d__0.<>s__4"" + IL_0049: ldarg.0 + IL_004a: ldfld ""int C.d__0.<>s__2"" + IL_004f: ldelem.r8 + IL_0050: box ""double"" + IL_0055: stfld ""object C.d__0.5__3"" + IL_005a: nop + IL_005b: ldarg.0 + IL_005c: ldc.i4.1 + IL_005d: stfld ""int C.d__0.<>2__current"" + IL_0062: ldarg.0 + IL_0063: ldc.i4.1 + IL_0064: stfld ""int C.d__0.<>1__state"" + IL_0069: ldc.i4.1 + IL_006a: ret + IL_006b: ldarg.0 + IL_006c: ldc.i4.m1 + IL_006d: stfld ""int C.d__0.<>1__state"" + IL_0072: nop + IL_0073: ldarg.0 + IL_0074: ldnull + IL_0075: stfld ""object C.d__0.5__3"" + IL_007a: ldarg.0 + IL_007b: ldarg.0 + IL_007c: ldfld ""int C.d__0.<>s__2"" + IL_0081: ldc.i4.1 + IL_0082: add + IL_0083: stfld ""int C.d__0.<>s__2"" + IL_0088: ldarg.0 + IL_0089: ldfld ""int C.d__0.<>s__2"" + IL_008e: ldarg.0 + IL_008f: ldfld ""double[] C.d__0.<>s__4"" + IL_0094: ldlen + IL_0095: conv.i4 + IL_0096: blt.s IL_0042 + IL_0098: ldarg.0 + IL_0099: ldnull + IL_009a: stfld ""double[] C.d__0.<>s__4"" + IL_009f: ldc.i4.0 + IL_00a0: ret +}"); + } + + [Fact] + public void UpdateIterator_YieldReturn_Add() + { + var source0 = MarkedSource(@" +using System.Collections.Generic; + +class C +{ + static int M1() => 1; + static int M2() => 2; + static int M3() => 3; + static int M4() => 4; + static void End() {} + + static IEnumerable F() + { + yield return M1(); + yield return M2(); + End(); + } +}"); + var source1 = MarkedSource(@" +using System.Collections.Generic; + +class C +{ + static int M1() => 1; + static int M2() => 2; + static int M3() => 3; + static int M4() => 4; + static void End() {} + + static IEnumerable F() + { + yield return M1(); + yield return M3(); + yield return M4(); + yield return M2(); + End(); + } +}"); + var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); + + var v0 = CompileAndVerify(compilation0); + v0.VerifyDiagnostics(); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + v0.VerifyPdb("C.F", @" + + + + + + + + + + + + + + + + +"); + v0.VerifyPdb("C+d__5.MoveNext", @" + + + + + + + + + + + + + + + +", options: PdbValidationOptions.ExcludeSequencePoints); + + v0.VerifyIL("C.d__5.System.Collections.IEnumerator.MoveNext", @" + { + // Code size 105 (0x69) + .maxstack 2 + .locals init (int V_0) + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__5.<>1__state"" + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: switch ( + IL_001b, + IL_001d, + IL_001f) + IL_0019: br.s IL_0021 + IL_001b: br.s IL_0023 + IL_001d: br.s IL_003f + IL_001f: br.s IL_005a + + IL_0021: ldc.i4.0 + IL_0022: ret + + IL_0023: ldarg.0 + IL_0024: ldc.i4.m1 + IL_0025: stfld ""int C.d__5.<>1__state"" + IL_002a: nop + IL_002b: ldarg.0 + IL_002c: call ""int C.M1()"" + IL_0031: stfld ""int C.d__5.<>2__current"" + IL_0036: ldarg.0 + IL_0037: ldc.i4.1 + IL_0038: stfld ""int C.d__5.<>1__state"" + IL_003d: ldc.i4.1 + IL_003e: ret + + IL_003f: ldarg.0 + IL_0040: ldc.i4.m1 + IL_0041: stfld ""int C.d__5.<>1__state"" + IL_0046: ldarg.0 + IL_0047: call ""int C.M2()"" + IL_004c: stfld ""int C.d__5.<>2__current"" + IL_0051: ldarg.0 + IL_0052: ldc.i4.2 + IL_0053: stfld ""int C.d__5.<>1__state"" + IL_0058: ldc.i4.1 + IL_0059: ret + + IL_005a: ldarg.0 + IL_005b: ldc.i4.m1 + IL_005c: stfld ""int C.d__5.<>1__state"" + IL_0061: call ""void C.End()"" + IL_0066: nop + IL_0067: ldc.i4.0 + IL_0068: ret +}"); + + diff1.VerifyIL("C.d__5.System.Collections.IEnumerator.MoveNext", @" +{ + // Code size 171 (0xab) + .maxstack 2 + .locals init (int V_0) + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__5.<>1__state"" + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: switch ( + IL_0023, + IL_0025, + IL_0027, + IL_0029, + IL_002b) + IL_0021: br.s IL_002d + IL_0023: br.s IL_002f + IL_0025: br.s IL_004b + IL_0027: br.s IL_009c + IL_0029: br.s IL_0066 + IL_002b: br.s IL_0081 + + IL_002d: ldc.i4.0 + IL_002e: ret + + IL_002f: ldarg.0 + IL_0030: ldc.i4.m1 + IL_0031: stfld ""int C.d__5.<>1__state"" + IL_0036: nop + IL_0037: ldarg.0 + IL_0038: call ""int C.M1()"" + IL_003d: stfld ""int C.d__5.<>2__current"" + IL_0042: ldarg.0 + IL_0043: ldc.i4.1 + IL_0044: stfld ""int C.d__5.<>1__state"" + IL_0049: ldc.i4.1 + IL_004a: ret + + IL_004b: ldarg.0 + IL_004c: ldc.i4.m1 + IL_004d: stfld ""int C.d__5.<>1__state"" + IL_0052: ldarg.0 + IL_0053: call ""int C.M3()"" + IL_0058: stfld ""int C.d__5.<>2__current"" + IL_005d: ldarg.0 + IL_005e: ldc.i4.3 + IL_005f: stfld ""int C.d__5.<>1__state"" + IL_0064: ldc.i4.1 + IL_0065: ret + + IL_0066: ldarg.0 + IL_0067: ldc.i4.m1 + IL_0068: stfld ""int C.d__5.<>1__state"" + IL_006d: ldarg.0 + IL_006e: call ""int C.M4()"" + IL_0073: stfld ""int C.d__5.<>2__current"" + IL_0078: ldarg.0 + IL_0079: ldc.i4.4 + IL_007a: stfld ""int C.d__5.<>1__state"" + IL_007f: ldc.i4.1 + IL_0080: ret + + IL_0081: ldarg.0 + IL_0082: ldc.i4.m1 + IL_0083: stfld ""int C.d__5.<>1__state"" + IL_0088: ldarg.0 + IL_0089: call ""int C.M2()"" + IL_008e: stfld ""int C.d__5.<>2__current"" + IL_0093: ldarg.0 + IL_0094: ldc.i4.2 + IL_0095: stfld ""int C.d__5.<>1__state"" + IL_009a: ldc.i4.1 + IL_009b: ret + + IL_009c: ldarg.0 + IL_009d: ldc.i4.m1 + IL_009e: stfld ""int C.d__5.<>1__state"" + IL_00a3: call ""void C.End()"" + IL_00a8: nop + IL_00a9: ldc.i4.0 + IL_00aa: ret +} +"); + } + + [Fact] + public void UpdateIterator_YieldReturn_Remove() + { + var source0 = MarkedSource(@" +using System.Collections.Generic; + +class C +{ + static int M1() => 1; + static int M2() => 2; + static int M3() => 3; + static int M4() => 4; + static void End() {} + + static IEnumerable F() + { + yield return M1(); + yield return M2(); + yield return M3(); + yield return M4(); + End(); + } +}"); + var source1 = MarkedSource(@" +using System.Collections.Generic; + +class C +{ + static int M1() => 1; + static int M2() => 2; + static int M3() => 3; + static int M4() => 4; + static void End() {} + + static IEnumerable F() + { + yield return M2(); + yield return M3(); + End(); + } +}"); + var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); + + var v0 = CompileAndVerify(compilation0); + v0.VerifyDiagnostics(); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + diff1.VerifyIL("C.d__5.System.Collections.IEnumerator.MoveNext", @" +{ + // Code size 124 (0x7c) + .maxstack 2 + .locals init (int V_0) + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__5.<>1__state"" + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: switch ( + IL_001f, + IL_0025, + IL_0021, + IL_0023) + IL_001d: br.s IL_0025 + IL_001f: br.s IL_0036 + IL_0021: br.s IL_0052 + IL_0023: br.s IL_006d + IL_0025: ldloc.0 + IL_0026: ldc.i4.1 + IL_0027: blt.s IL_0034 + IL_0029: ldstr """ + CodeAnalysisResources.EncCannotResumeSuspendedIteratorMethod + @""" + IL_002e: newobj ""System.InvalidOperationException..ctor(string)"" + IL_0033: throw + + IL_0034: ldc.i4.0 + IL_0035: ret + + IL_0036: ldarg.0 + IL_0037: ldc.i4.m1 + IL_0038: stfld ""int C.d__5.<>1__state"" + IL_003d: nop + IL_003e: ldarg.0 + IL_003f: call ""int C.M2()"" + IL_0044: stfld ""int C.d__5.<>2__current"" + IL_0049: ldarg.0 + IL_004a: ldc.i4.2 + IL_004b: stfld ""int C.d__5.<>1__state"" + IL_0050: ldc.i4.1 + IL_0051: ret + + IL_0052: ldarg.0 + IL_0053: ldc.i4.m1 + IL_0054: stfld ""int C.d__5.<>1__state"" + IL_0059: ldarg.0 + IL_005a: call ""int C.M3()"" + IL_005f: stfld ""int C.d__5.<>2__current"" + IL_0064: ldarg.0 + IL_0065: ldc.i4.3 + IL_0066: stfld ""int C.d__5.<>1__state"" + IL_006b: ldc.i4.1 + IL_006c: ret + + IL_006d: ldarg.0 + IL_006e: ldc.i4.m1 + IL_006f: stfld ""int C.d__5.<>1__state"" + IL_0074: call ""void C.End()"" + IL_0079: nop + IL_007a: ldc.i4.0 + IL_007b: ret +} +"); + } + + [Fact] + public void UpdateIterator_YieldReturn_Add_Finally_Try() + { + var source0 = MarkedSource(@" +using System.Collections.Generic; + +class C +{ + static IEnumerable F() + { + yield return M1(); + + try + { + yield return M2(); + } + finally + { + Finally1(0); + } + + yield return M3(); + + End(); + } + + static int M1() => 1; + static int M2() => 2; + static int M3() => 3; + static int M4() => 4; + static void End() {} + static void Finally1(int gen) {} + static void Finally2(int gen) {} + static void Finally3(int gen) {} +}"); + var source1 = MarkedSource(@" +using System.Collections.Generic; + +class C +{ + static IEnumerable F() + { + try + { + yield return M1(); + } + finally + { + Finally2(1); + } + + try + { + yield return M2(); + try + { + yield return M4(); + } + finally + { + Finally3(1); + } + } + finally + { + Finally1(1); + } + + yield return M3(); + + End(); + } + + static int M1() => 1; + static int M2() => 2; + static int M3() => 3; + static int M4() => 4; + static void End() {} + static void Finally1(int gen) {} + static void Finally2(int gen) {} + static void Finally3(int gen) {} +}"); + var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); + + var v0 = CompileAndVerify(compilation0); + v0.VerifyDiagnostics(); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + v0.VerifyPdb("C.F", @" + + + + + + + + + + + + + + + + + +"); + + diff1.VerifySynthesizedMembers( + "C: {d__0}", + "C.d__0: {" + string.Join(", ", new[] + { + "<>1__state", + "<>2__current", + "<>l__initialThreadId", + "System.IDisposable.Dispose", + "MoveNext", + "<>m__Finally2", + "<>m__Finally1", + "<>m__Finally3", + "System.Collections.Generic.IEnumerator.get_Current", + "System.Collections.IEnumerator.Reset, System.Collections.IEnumerator.get_Current", + "System.Collections.Generic.IEnumerable.GetEnumerator", + "System.Collections.IEnumerable.GetEnumerator", + "System.Collections.Generic.IEnumerator.Current", + "System.Collections.IEnumerator.Current" + }) + "}"); + + diff1.VerifyIL("C.d__0.<>m__Finally1", @" +{ + // Code size 17 (0x11) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.m1 + IL_0002: stfld ""int C.d__0.<>1__state"" + IL_0007: nop + IL_0008: ldc.i4.1 + IL_0009: call ""void C.Finally1(int)"" + IL_000e: nop + IL_000f: nop + IL_0010: ret +} +"); + diff1.VerifyIL("C.d__0.<>m__Finally2", @" +{ + // Code size 17 (0x11) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.m1 + IL_0002: stfld ""int C.d__0.<>1__state"" + IL_0007: nop + IL_0008: ldc.i4.1 + IL_0009: call ""void C.Finally2(int)"" + IL_000e: nop + IL_000f: nop + IL_0010: ret +} +"); + diff1.VerifyIL("C.d__0.<>m__Finally3", @" +{ + // Code size 18 (0x12) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.s -3 + IL_0003: stfld ""int C.d__0.<>1__state"" + IL_0008: nop + IL_0009: ldc.i4.1 + IL_000a: call ""void C.Finally3(int)"" + IL_000f: nop + IL_0010: nop + IL_0011: ret +} +"); + + v0.VerifyIL("C.d__0.System.IDisposable.Dispose", @" +{ + // Code size 33 (0x21) + .maxstack 2 + .locals init (int V_0) + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__0.<>1__state"" + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: ldc.i4.s -3 + IL_000a: beq.s IL_0014 + IL_000c: br.s IL_000e + IL_000e: ldloc.0 + IL_000f: ldc.i4.2 + IL_0010: beq.s IL_0014 + IL_0012: br.s IL_0020 + IL_0014: nop + .try + { + IL_0015: leave.s IL_001e + } + finally + { + IL_0017: ldarg.0 + IL_0018: call ""void C.d__0.<>m__Finally1()"" + IL_001d: endfinally + } + IL_001e: br.s IL_0020 + IL_0020: ret +} +"); + diff1.VerifyIL("C.d__0.System.IDisposable.Dispose", @" +{ + // Code size 108 (0x6c) + .maxstack 2 + .locals init (int V_0) + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__0.<>1__state"" + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: ldc.i4.s -5 + IL_000a: sub + IL_000b: switch ( + IL_0046, + IL_003a, + IL_0046, + IL_006b, + IL_006b, + IL_006b, + IL_003a, + IL_0046, + IL_006b, + IL_0046) + IL_0038: br.s IL_006b + IL_003a: nop + .try + { + IL_003b: leave.s IL_0044 + } + finally + { + IL_003d: ldarg.0 + IL_003e: call ""void C.d__0.<>m__Finally2()"" + IL_0043: endfinally + } + IL_0044: br.s IL_006b + IL_0046: nop + .try + { + IL_0047: ldloc.0 + IL_0048: ldc.i4.s -5 + IL_004a: beq.s IL_0054 + IL_004c: br.s IL_004e + IL_004e: ldloc.0 + IL_004f: ldc.i4.4 + IL_0050: beq.s IL_0054 + IL_0052: br.s IL_0060 + IL_0054: nop + .try + { + IL_0055: leave.s IL_005e + } + finally + { + IL_0057: ldarg.0 + IL_0058: call ""void C.d__0.<>m__Finally3()"" + IL_005d: endfinally + } + IL_005e: br.s IL_0060 + IL_0060: leave.s IL_0069 + } + finally + { + IL_0062: ldarg.0 + IL_0063: call ""void C.d__0.<>m__Finally1()"" + IL_0068: endfinally + } + IL_0069: br.s IL_006b + IL_006b: ret +} +"); + + v0.VerifyIL("C.d__0.System.Collections.IEnumerator.MoveNext", @" +{ + // Code size 179 (0xb3) + .maxstack 2 + .locals init (bool V_0, + int V_1) + .try + { + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__0.<>1__state"" + IL_0006: stloc.1 + IL_0007: ldloc.1 + IL_0008: switch ( + IL_001f, + IL_0021, + IL_0023, + IL_0025) + IL_001d: br.s IL_0027 + IL_001f: br.s IL_002e + IL_0021: br.s IL_004c + IL_0023: br.s IL_0072 + IL_0025: br.s IL_0098 + IL_0027: ldc.i4.0 + IL_0028: stloc.0 + IL_0029: leave IL_00b1 + IL_002e: ldarg.0 + IL_002f: ldc.i4.m1 + IL_0030: stfld ""int C.d__0.<>1__state"" + IL_0035: nop + IL_0036: ldarg.0 + IL_0037: call ""int C.M1()"" + IL_003c: stfld ""int C.d__0.<>2__current"" + IL_0041: ldarg.0 + IL_0042: ldc.i4.1 + IL_0043: stfld ""int C.d__0.<>1__state"" + IL_0048: ldc.i4.1 + IL_0049: stloc.0 + IL_004a: leave.s IL_00b1 + IL_004c: ldarg.0 + IL_004d: ldc.i4.m1 + IL_004e: stfld ""int C.d__0.<>1__state"" + IL_0053: ldarg.0 + IL_0054: ldc.i4.s -3 + IL_0056: stfld ""int C.d__0.<>1__state"" + IL_005b: nop + IL_005c: ldarg.0 + IL_005d: call ""int C.M2()"" + IL_0062: stfld ""int C.d__0.<>2__current"" + IL_0067: ldarg.0 + IL_0068: ldc.i4.2 + IL_0069: stfld ""int C.d__0.<>1__state"" + IL_006e: ldc.i4.1 + IL_006f: stloc.0 + IL_0070: leave.s IL_00b1 + IL_0072: ldarg.0 + IL_0073: ldc.i4.s -3 + IL_0075: stfld ""int C.d__0.<>1__state"" + IL_007a: nop + IL_007b: ldarg.0 + IL_007c: call ""void C.d__0.<>m__Finally1()"" + IL_0081: nop + IL_0082: ldarg.0 + IL_0083: call ""int C.M3()"" + IL_0088: stfld ""int C.d__0.<>2__current"" + IL_008d: ldarg.0 + IL_008e: ldc.i4.3 + IL_008f: stfld ""int C.d__0.<>1__state"" + IL_0094: ldc.i4.1 + IL_0095: stloc.0 + IL_0096: leave.s IL_00b1 + IL_0098: ldarg.0 + IL_0099: ldc.i4.m1 + IL_009a: stfld ""int C.d__0.<>1__state"" + IL_009f: call ""void C.End()"" + IL_00a4: nop + IL_00a5: ldc.i4.0 + IL_00a6: stloc.0 + IL_00a7: leave.s IL_00b1 + } + fault + { + IL_00a9: ldarg.0 + IL_00aa: call ""void C.d__0.Dispose()"" + IL_00af: nop + IL_00b0: endfinally + } + IL_00b1: ldloc.0 + IL_00b2: ret +} +"); + + diff1.VerifyIL("C.d__0.System.Collections.IEnumerator.MoveNext", @" +{ + // Code size 259 (0x103) + .maxstack 2 + .locals init (bool V_0, + int V_1) + .try + { + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__0.<>1__state"" + IL_0006: stloc.1 + IL_0007: ldloc.1 + IL_0008: switch ( + IL_0023, + IL_0025, + IL_0027, + IL_0029, + IL_002e) + IL_0021: br.s IL_0033 + IL_0023: br.s IL_003a + IL_0025: br.s IL_0064 + IL_0027: br.s IL_0093 + IL_0029: br IL_00e8 + IL_002e: br IL_00ba + IL_0033: ldc.i4.0 + IL_0034: stloc.0 + IL_0035: leave IL_0101 + IL_003a: ldarg.0 + IL_003b: ldc.i4.m1 + IL_003c: stfld ""int C.d__0.<>1__state"" + IL_0041: nop + IL_0042: ldarg.0 + IL_0043: ldc.i4.s -4 + IL_0045: stfld ""int C.d__0.<>1__state"" + IL_004a: nop + IL_004b: ldarg.0 + IL_004c: call ""int C.M1()"" + IL_0051: stfld ""int C.d__0.<>2__current"" + IL_0056: ldarg.0 + IL_0057: ldc.i4.1 + IL_0058: stfld ""int C.d__0.<>1__state"" + IL_005d: ldc.i4.1 + IL_005e: stloc.0 + IL_005f: leave IL_0101 + IL_0064: ldarg.0 + IL_0065: ldc.i4.s -4 + IL_0067: stfld ""int C.d__0.<>1__state"" + IL_006c: nop + IL_006d: ldarg.0 + IL_006e: call ""void C.d__0.<>m__Finally2()"" + IL_0073: nop + IL_0074: ldarg.0 + IL_0075: ldc.i4.s -3 + IL_0077: stfld ""int C.d__0.<>1__state"" + IL_007c: nop + IL_007d: ldarg.0 + IL_007e: call ""int C.M2()"" + IL_0083: stfld ""int C.d__0.<>2__current"" + IL_0088: ldarg.0 + IL_0089: ldc.i4.2 + IL_008a: stfld ""int C.d__0.<>1__state"" + IL_008f: ldc.i4.1 + IL_0090: stloc.0 + IL_0091: leave.s IL_0101 + IL_0093: ldarg.0 + IL_0094: ldc.i4.s -3 + IL_0096: stfld ""int C.d__0.<>1__state"" + IL_009b: ldarg.0 + IL_009c: ldc.i4.s -5 + IL_009e: stfld ""int C.d__0.<>1__state"" + IL_00a3: nop + IL_00a4: ldarg.0 + IL_00a5: call ""int C.M4()"" + IL_00aa: stfld ""int C.d__0.<>2__current"" + IL_00af: ldarg.0 + IL_00b0: ldc.i4.4 + IL_00b1: stfld ""int C.d__0.<>1__state"" + IL_00b6: ldc.i4.1 + IL_00b7: stloc.0 + IL_00b8: leave.s IL_0101 + IL_00ba: ldarg.0 + IL_00bb: ldc.i4.s -5 + IL_00bd: stfld ""int C.d__0.<>1__state"" + IL_00c2: nop + IL_00c3: ldarg.0 + IL_00c4: call ""void C.d__0.<>m__Finally3()"" + IL_00c9: nop + IL_00ca: nop + IL_00cb: ldarg.0 + IL_00cc: call ""void C.d__0.<>m__Finally1()"" + IL_00d1: nop + IL_00d2: ldarg.0 + IL_00d3: call ""int C.M3()"" + IL_00d8: stfld ""int C.d__0.<>2__current"" + IL_00dd: ldarg.0 + IL_00de: ldc.i4.3 + IL_00df: stfld ""int C.d__0.<>1__state"" + IL_00e4: ldc.i4.1 + IL_00e5: stloc.0 + IL_00e6: leave.s IL_0101 + IL_00e8: ldarg.0 + IL_00e9: ldc.i4.m1 + IL_00ea: stfld ""int C.d__0.<>1__state"" + IL_00ef: call ""void C.End()"" + IL_00f4: nop + IL_00f5: ldc.i4.0 + IL_00f6: stloc.0 + IL_00f7: leave.s IL_0101 + } + fault + { + IL_00f9: ldarg.0 + IL_00fa: call ""void C.d__0.Dispose()"" + IL_00ff: nop + IL_0100: endfinally + } + IL_0101: ldloc.0 + IL_0102: ret }"); - } - } } [Fact] - public void UpdateIterator_UserDefinedVariables_AddVariable() + public void UpdateIterator_YieldReturn_Add_Finally_UsingDeclaration() { - var source0 = @" + var source0 = MarkedSource(@" using System; using System.Collections.Generic; class C { - static IEnumerable F(int p) + static IEnumerable F() { - int x = p; - yield return x; + using var x = M1(); + yield return M2(); + End(); } -}"; - var source1 = @" + + static IDisposable M1() => null; + static int M2() => 0; + static int M3() => 0; + static void End() {} +}"); + var source1 = MarkedSource(@" using System; using System.Collections.Generic; class C { - static IEnumerable F(int p) + static IEnumerable F() { - int y = 1234; - int x = p; - yield return y; - Console.WriteLine(x); + using var x = M1(); + yield return M2(); + yield return M3(); + End(); } -}"; - var compilation0 = CreateCompilationWithMscorlib45(source0, options: ComSafeDebugDll); - var compilation1 = compilation0.WithSource(source1); + + static IDisposable M1() => null; + static int M2() => 0; + static int M3() => 0; + static void End() {} +}"); + var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemCoreRef, CSharpRef }, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); var v0 = CompileAndVerify(compilation0); - var symReader = v0.CreateSymReader(); + v0.VerifyDiagnostics(); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); - using (var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData)) - { - var method0 = compilation0.GetMember("C.F"); - var method1 = compilation1.GetMember("C.F"); + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); - var generation0 = EmitBaseline.CreateInitialBaseline(md0, symReader.GetEncMethodDebugInfo); - var diff1 = compilation1.EmitDifference( - generation0, - ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1, GetEquivalentNodesMap(method1, method0), preserveLocalVariables: true))); + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); - // Verify delta metadata contains expected rows. - using (var md1 = diff1.GetMetadata()) - { - // 1 field def added & 3 methods updated - CheckEncLogDefinitions(md1.Reader, - Row(3, TableIndex.StandAloneSig, EditAndContinueOperation.Default), - Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), - Row(7, TableIndex.Field, EditAndContinueOperation.Default), - Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(1, TableIndex.Param, EditAndContinueOperation.Default), - Row(1, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + v0.VerifyPdb("C.F", @" + + + + + + + + + + + + + + + + + + +"); + + diff1.VerifySynthesizedMembers( + "C: {d__0}", + "C.d__0: {" + string.Join(", ", new[] + { + "<>1__state", + "<>2__current", + "<>l__initialThreadId", + "5__1", + "System.IDisposable.Dispose", + "MoveNext", + "<>m__Finally1", + "System.Collections.Generic.IEnumerator.get_Current", + "System.Collections.IEnumerator.Reset, System.Collections.IEnumerator.get_Current", + "System.Collections.Generic.IEnumerable.GetEnumerator", + "System.Collections.IEnumerable.GetEnumerator", + "System.Collections.Generic.IEnumerator.Current", + "System.Collections.IEnumerator.Current" + }) + "}"); + + diff1.VerifyIL("C.d__0.<>m__Finally1", @" +{ + // Code size 28 (0x1c) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldc.i4.m1 + IL_0002: stfld ""int C.d__0.<>1__state"" + IL_0007: ldarg.0 + IL_0008: ldfld ""System.IDisposable C.d__0.5__1"" + IL_000d: brfalse.s IL_001b + IL_000f: ldarg.0 + IL_0010: ldfld ""System.IDisposable C.d__0.5__1"" + IL_0015: callvirt ""void System.IDisposable.Dispose()"" + IL_001a: nop + IL_001b: ret +} +"); - diff1.VerifyIL("C.d__0.System.Collections.IEnumerator.MoveNext", @" + v0.VerifyIL("C.d__0.System.IDisposable.Dispose", @" { - // Code size 97 (0x61) + // Code size 33 (0x21) .maxstack 2 .locals init (int V_0) IL_0000: ldarg.0 IL_0001: ldfld ""int C.d__0.<>1__state"" IL_0006: stloc.0 IL_0007: ldloc.0 - IL_0008: brfalse.s IL_0012 - IL_000a: br.s IL_000c - IL_000c: ldloc.0 - IL_000d: ldc.i4.1 - IL_000e: beq.s IL_0014 - IL_0010: br.s IL_0016 - IL_0012: br.s IL_0018 - IL_0014: br.s IL_004c - IL_0016: ldc.i4.0 - IL_0017: ret - IL_0018: ldarg.0 - IL_0019: ldc.i4.m1 - IL_001a: stfld ""int C.d__0.<>1__state"" - IL_001f: nop - IL_0020: ldarg.0 - IL_0021: ldc.i4 0x4d2 - IL_0026: stfld ""int C.d__0.5__2"" - IL_002b: ldarg.0 - IL_002c: ldarg.0 - IL_002d: ldfld ""int C.d__0.p"" - IL_0032: stfld ""int C.d__0.5__1"" - IL_0037: ldarg.0 - IL_0038: ldarg.0 - IL_0039: ldfld ""int C.d__0.5__2"" - IL_003e: stfld ""int C.d__0.<>2__current"" - IL_0043: ldarg.0 - IL_0044: ldc.i4.1 - IL_0045: stfld ""int C.d__0.<>1__state"" - IL_004a: ldc.i4.1 - IL_004b: ret - IL_004c: ldarg.0 - IL_004d: ldc.i4.m1 - IL_004e: stfld ""int C.d__0.<>1__state"" - IL_0053: ldarg.0 - IL_0054: ldfld ""int C.d__0.5__1"" - IL_0059: call ""void System.Console.WriteLine(int)"" - IL_005e: nop - IL_005f: ldc.i4.0 - IL_0060: ret + IL_0008: ldc.i4.s -3 + IL_000a: beq.s IL_0014 + IL_000c: br.s IL_000e + IL_000e: ldloc.0 + IL_000f: ldc.i4.1 + IL_0010: beq.s IL_0014 + IL_0012: br.s IL_0020 + IL_0014: nop + .try + { + IL_0015: leave.s IL_001e + } + finally + { + IL_0017: ldarg.0 + IL_0018: call ""void C.d__0.<>m__Finally1()"" + IL_001d: endfinally + } + IL_001e: br.s IL_0020 + IL_0020: ret +} +"); + diff1.VerifyIL("C.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.d__0.<>1__state"" + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: ldc.i4.s -3 + IL_000a: beq.s IL_0016 + IL_000c: br.s IL_000e + IL_000e: ldloc.0 + IL_000f: ldc.i4.1 + IL_0010: sub + IL_0011: ldc.i4.1 + IL_0012: ble.un.s IL_0016 + IL_0014: br.s IL_0022 + IL_0016: nop + .try + { + IL_0017: leave.s IL_0020 + } + finally + { + IL_0019: ldarg.0 + IL_001a: call ""void C.d__0.<>m__Finally1()"" + IL_001f: endfinally + } + IL_0020: br.s IL_0022 + IL_0022: ret +} +"); + + v0.VerifyIL("C.d__0.System.Collections.IEnumerator.MoveNext", @" + { + // Code size 112 (0x70) + .maxstack 2 + .locals init (bool V_0, + int V_1) + .try + { + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__0.<>1__state"" + IL_0006: stloc.1 + IL_0007: ldloc.1 + IL_0008: brfalse.s IL_0012 + IL_000a: br.s IL_000c + IL_000c: ldloc.1 + IL_000d: ldc.i4.1 + IL_000e: beq.s IL_0014 + IL_0010: br.s IL_0016 + IL_0012: br.s IL_001a + IL_0014: br.s IL_004b + IL_0016: ldc.i4.0 + IL_0017: stloc.0 + IL_0018: leave.s IL_006e + IL_001a: ldarg.0 + IL_001b: ldc.i4.m1 + IL_001c: stfld ""int C.d__0.<>1__state"" + IL_0021: nop + IL_0022: ldarg.0 + IL_0023: call ""System.IDisposable C.M1()"" + IL_0028: stfld ""System.IDisposable C.d__0.5__1"" + IL_002d: ldarg.0 + IL_002e: ldc.i4.s -3 + IL_0030: stfld ""int C.d__0.<>1__state"" + IL_0035: ldarg.0 + IL_0036: call ""int C.M2()"" + IL_003b: stfld ""int C.d__0.<>2__current"" + IL_0040: ldarg.0 + IL_0041: ldc.i4.1 + IL_0042: stfld ""int C.d__0.<>1__state"" + IL_0047: ldc.i4.1 + IL_0048: stloc.0 + IL_0049: leave.s IL_006e + IL_004b: ldarg.0 + IL_004c: ldc.i4.s -3 + IL_004e: stfld ""int C.d__0.<>1__state"" + IL_0053: call ""void C.End()"" + IL_0058: nop + IL_0059: ldc.i4.0 + IL_005a: stloc.0 + IL_005b: br.s IL_005d + IL_005d: ldarg.0 + IL_005e: call ""void C.d__0.<>m__Finally1()"" + IL_0063: nop + IL_0064: leave.s IL_006e + } + fault + { + IL_0066: ldarg.0 + IL_0067: call ""void C.d__0.Dispose()"" + IL_006c: nop + IL_006d: endfinally + } + IL_006e: ldloc.0 + IL_006f: ret +} +"); + + diff1.VerifyIL("C.d__0.System.Collections.IEnumerator.MoveNext", @" +{ + // Code size 153 (0x99) + .maxstack 2 + .locals init (bool V_0, + int V_1) + .try + { + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__0.<>1__state"" + IL_0006: stloc.1 + IL_0007: ldloc.1 + IL_0008: switch ( + IL_001b, + IL_001d, + IL_001f) + IL_0019: br.s IL_0021 + IL_001b: br.s IL_0025 + IL_001d: br.s IL_0056 + IL_001f: br.s IL_0074 + IL_0021: ldc.i4.0 + IL_0022: stloc.0 + IL_0023: leave.s IL_0097 + IL_0025: ldarg.0 + IL_0026: ldc.i4.m1 + IL_0027: stfld ""int C.d__0.<>1__state"" + IL_002c: nop + IL_002d: ldarg.0 + IL_002e: call ""System.IDisposable C.M1()"" + IL_0033: stfld ""System.IDisposable C.d__0.5__1"" + IL_0038: ldarg.0 + IL_0039: ldc.i4.s -3 + IL_003b: stfld ""int C.d__0.<>1__state"" + IL_0040: ldarg.0 + IL_0041: call ""int C.M2()"" + IL_0046: stfld ""int C.d__0.<>2__current"" + IL_004b: ldarg.0 + IL_004c: ldc.i4.1 + IL_004d: stfld ""int C.d__0.<>1__state"" + IL_0052: ldc.i4.1 + IL_0053: stloc.0 + IL_0054: leave.s IL_0097 + IL_0056: ldarg.0 + IL_0057: ldc.i4.s -3 + IL_0059: stfld ""int C.d__0.<>1__state"" + IL_005e: ldarg.0 + IL_005f: call ""int C.M3()"" + IL_0064: stfld ""int C.d__0.<>2__current"" + IL_0069: ldarg.0 + IL_006a: ldc.i4.2 + IL_006b: stfld ""int C.d__0.<>1__state"" + IL_0070: ldc.i4.1 + IL_0071: stloc.0 + IL_0072: leave.s IL_0097 + IL_0074: ldarg.0 + IL_0075: ldc.i4.s -3 + IL_0077: stfld ""int C.d__0.<>1__state"" + IL_007c: call ""void C.End()"" + IL_0081: nop + IL_0082: ldc.i4.0 + IL_0083: stloc.0 + IL_0084: br.s IL_0086 + IL_0086: ldarg.0 + IL_0087: call ""void C.d__0.<>m__Finally1()"" + IL_008c: nop + IL_008d: leave.s IL_0097 + } + fault + { + IL_008f: ldarg.0 + IL_0090: call ""void C.d__0.Dispose()"" + IL_0095: nop + IL_0096: endfinally + } + IL_0097: ldloc.0 + IL_0098: ret }"); - } - } } [Fact] - public void UpdateIterator_UserDefinedVariables_AddAndRemoveVariable() + public void UpdateIterator_YieldReturn_Add_Finally_Foreach_ForEachVar_Using_Lock() { - var source0 = @" + var source0 = MarkedSource(@" using System; using System.Collections.Generic; class C { - static IEnumerable F(int p) + static IEnumerable F() { - int x = p; - yield return x; + using IDisposable x1 = D(), x2 = D(); + + using (D()) + using (IDisposable y1 = D(), y2 = D()) + foreach (var z in E()) + foreach (var (u, w) in E()) + lock (D()) + { + yield return 1; + } } -}"; - var source1 = @" + + static IDisposable D() => null; + static IEnumerable<(int, int)> E() => null; +}"); + var source1 = MarkedSource(@" using System; using System.Collections.Generic; class C { - static IEnumerable F(int p) + static IEnumerable F() { - int y = 1234; - yield return y; - Console.WriteLine(p); + using IDisposable x1 = D(), x2 = D(); + + using (D()) + using (IDisposable y1 = D(), y2 = D()) + foreach (var z in E()) + foreach (var (u, w) in E()) + lock (D()) + { + yield return 1; + yield return 2; + } } -}"; - var compilation0 = CreateCompilationWithMscorlib45(source0, options: ComSafeDebugDll); - var compilation1 = compilation0.WithSource(source1); + + static IDisposable D() => null; + static IEnumerable<(int, int)> E() => null; +}"); + var compilation0 = CreateCompilationWithMscorlib45(new[] { source0.Tree }, new[] { SystemRuntimeFacadeRef, ValueTupleRef }, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); var v0 = CompileAndVerify(compilation0); - var symReader = v0.CreateSymReader(); + v0.VerifyDiagnostics(); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); - using (var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData)) - { - var method0 = compilation0.GetMember("C.F"); - var method1 = compilation1.GetMember("C.F"); + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); - var generation0 = EmitBaseline.CreateInitialBaseline(md0, symReader.GetEncMethodDebugInfo); - var diff1 = compilation1.EmitDifference( - generation0, - ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1, GetEquivalentNodesMap(method1, method0), preserveLocalVariables: true))); + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); - // Verify delta metadata contains expected rows. - using (var md1 = diff1.GetMetadata()) - { - // 1 field def added & 3 methods updated - CheckEncLogDefinitions(md1.Reader, - Row(3, TableIndex.StandAloneSig, EditAndContinueOperation.Default), - Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), - Row(7, TableIndex.Field, EditAndContinueOperation.Default), - Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(1, TableIndex.Param, EditAndContinueOperation.Default), - Row(1, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + v0.VerifyPdb("C.F", @" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"); - diff1.VerifyIL("C.d__0.System.Collections.IEnumerator.MoveNext", @" + diff1.VerifyIL("C.d__0.System.Collections.IEnumerator.MoveNext", @" { - // Code size 85 (0x55) + // Code size 526 (0x20e) .maxstack 2 - .locals init (int V_0) - IL_0000: ldarg.0 - IL_0001: ldfld ""int C.d__0.<>1__state"" - IL_0006: stloc.0 - IL_0007: ldloc.0 - IL_0008: brfalse.s IL_0012 - IL_000a: br.s IL_000c - IL_000c: ldloc.0 - IL_000d: ldc.i4.1 - IL_000e: beq.s IL_0014 - IL_0010: br.s IL_0016 - IL_0012: br.s IL_0018 - IL_0014: br.s IL_0040 - IL_0016: ldc.i4.0 - IL_0017: ret - IL_0018: ldarg.0 - IL_0019: ldc.i4.m1 - IL_001a: stfld ""int C.d__0.<>1__state"" - IL_001f: nop - IL_0020: ldarg.0 - IL_0021: ldc.i4 0x4d2 - IL_0026: stfld ""int C.d__0.5__2"" - IL_002b: ldarg.0 - IL_002c: ldarg.0 - IL_002d: ldfld ""int C.d__0.5__2"" - IL_0032: stfld ""int C.d__0.<>2__current"" - IL_0037: ldarg.0 - IL_0038: ldc.i4.1 - IL_0039: stfld ""int C.d__0.<>1__state"" - IL_003e: ldc.i4.1 - IL_003f: ret - IL_0040: ldarg.0 - IL_0041: ldc.i4.m1 - IL_0042: stfld ""int C.d__0.<>1__state"" - IL_0047: ldarg.0 - IL_0048: ldfld ""int C.d__0.p"" - IL_004d: call ""void System.Console.WriteLine(int)"" - IL_0052: nop - IL_0053: ldc.i4.0 - IL_0054: ret + .locals init (bool V_0, + int V_1, + System.ValueTuple V_2) + .try + { + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__0.<>1__state"" + IL_0006: stloc.1 + IL_0007: ldloc.1 + IL_0008: switch ( + IL_001b, + IL_001d, + IL_0022) + IL_0019: br.s IL_0027 + IL_001b: br.s IL_002e + IL_001d: br IL_0148 + IL_0022: br IL_0165 + IL_0027: ldc.i4.0 + IL_0028: stloc.0 + IL_0029: leave IL_020c + IL_002e: ldarg.0 + IL_002f: ldc.i4.m1 + IL_0030: stfld ""int C.d__0.<>1__state"" + IL_0035: nop + IL_0036: ldarg.0 + IL_0037: call ""System.IDisposable C.D()"" + IL_003c: stfld ""System.IDisposable C.d__0.5__1"" + IL_0041: ldarg.0 + IL_0042: ldc.i4.s -3 + IL_0044: stfld ""int C.d__0.<>1__state"" + IL_0049: ldarg.0 + IL_004a: call ""System.IDisposable C.D()"" + IL_004f: stfld ""System.IDisposable C.d__0.5__2"" + IL_0054: ldarg.0 + IL_0055: ldc.i4.s -4 + IL_0057: stfld ""int C.d__0.<>1__state"" + IL_005c: ldarg.0 + IL_005d: call ""System.IDisposable C.D()"" + IL_0062: stfld ""System.IDisposable C.d__0.<>s__3"" + IL_0067: ldarg.0 + IL_0068: ldc.i4.s -5 + IL_006a: stfld ""int C.d__0.<>1__state"" + IL_006f: ldarg.0 + IL_0070: call ""System.IDisposable C.D()"" + IL_0075: stfld ""System.IDisposable C.d__0.5__4"" + IL_007a: ldarg.0 + IL_007b: ldc.i4.s -6 + IL_007d: stfld ""int C.d__0.<>1__state"" + IL_0082: ldarg.0 + IL_0083: call ""System.IDisposable C.D()"" + IL_0088: stfld ""System.IDisposable C.d__0.5__5"" + IL_008d: ldarg.0 + IL_008e: ldc.i4.s -7 + IL_0090: stfld ""int C.d__0.<>1__state"" + IL_0095: nop + IL_0096: ldarg.0 + IL_0097: call ""System.Collections.Generic.IEnumerable> C.E()"" + IL_009c: callvirt ""System.Collections.Generic.IEnumerator> System.Collections.Generic.IEnumerable>.GetEnumerator()"" + IL_00a1: stfld ""System.Collections.Generic.IEnumerator> C.d__0.<>s__6"" + IL_00a6: ldarg.0 + IL_00a7: ldc.i4.s -8 + IL_00a9: stfld ""int C.d__0.<>1__state"" + IL_00ae: br IL_01a6 + IL_00b3: ldarg.0 + IL_00b4: ldarg.0 + IL_00b5: ldfld ""System.Collections.Generic.IEnumerator> C.d__0.<>s__6"" + IL_00ba: callvirt ""System.ValueTuple System.Collections.Generic.IEnumerator>.Current.get"" + IL_00bf: stfld ""System.ValueTuple C.d__0.5__7"" + IL_00c4: nop + IL_00c5: ldarg.0 + IL_00c6: call ""System.Collections.Generic.IEnumerable> C.E()"" + IL_00cb: callvirt ""System.Collections.Generic.IEnumerator> System.Collections.Generic.IEnumerable>.GetEnumerator()"" + IL_00d0: stfld ""System.Collections.Generic.IEnumerator> C.d__0.<>s__8"" + IL_00d5: ldarg.0 + IL_00d6: ldc.i4.s -9 + IL_00d8: stfld ""int C.d__0.<>1__state"" + IL_00dd: br IL_017c + IL_00e2: ldarg.0 + IL_00e3: ldfld ""System.Collections.Generic.IEnumerator> C.d__0.<>s__8"" + IL_00e8: callvirt ""System.ValueTuple System.Collections.Generic.IEnumerator>.Current.get"" + IL_00ed: stloc.2 + IL_00ee: ldarg.0 + IL_00ef: ldloc.2 + IL_00f0: ldfld ""int System.ValueTuple.Item1"" + IL_00f5: stfld ""int C.d__0.5__13"" + IL_00fa: ldarg.0 + IL_00fb: ldloc.2 + IL_00fc: ldfld ""int System.ValueTuple.Item2"" + IL_0101: stfld ""int C.d__0.5__14"" + IL_0106: ldarg.0 + IL_0107: call ""System.IDisposable C.D()"" + IL_010c: stfld ""System.IDisposable C.d__0.<>s__11"" + IL_0111: ldarg.0 + IL_0112: ldc.i4.0 + IL_0113: stfld ""bool C.d__0.<>s__12"" + IL_0118: ldarg.0 + IL_0119: ldc.i4.s -10 + IL_011b: stfld ""int C.d__0.<>1__state"" + IL_0120: ldarg.0 + IL_0121: ldfld ""System.IDisposable C.d__0.<>s__11"" + IL_0126: ldarg.0 + IL_0127: ldflda ""bool C.d__0.<>s__12"" + IL_012c: call ""void System.Threading.Monitor.Enter(object, ref bool)"" + IL_0131: nop + IL_0132: nop + IL_0133: ldarg.0 + IL_0134: ldc.i4.1 + IL_0135: stfld ""int C.d__0.<>2__current"" + IL_013a: ldarg.0 + IL_013b: ldc.i4.1 + IL_013c: stfld ""int C.d__0.<>1__state"" + IL_0141: ldc.i4.1 + IL_0142: stloc.0 + IL_0143: leave IL_020c + IL_0148: ldarg.0 + IL_0149: ldc.i4.s -10 + IL_014b: stfld ""int C.d__0.<>1__state"" + IL_0150: ldarg.0 + IL_0151: ldc.i4.2 + IL_0152: stfld ""int C.d__0.<>2__current"" + IL_0157: ldarg.0 + IL_0158: ldc.i4.2 + IL_0159: stfld ""int C.d__0.<>1__state"" + IL_015e: ldc.i4.1 + IL_015f: stloc.0 + IL_0160: leave IL_020c + IL_0165: ldarg.0 + IL_0166: ldc.i4.s -10 + IL_0168: stfld ""int C.d__0.<>1__state"" + IL_016d: nop + IL_016e: ldarg.0 + IL_016f: call ""void C.d__0.<>m__Finally8()"" + IL_0174: nop + IL_0175: ldarg.0 + IL_0176: ldnull + IL_0177: stfld ""System.IDisposable C.d__0.<>s__11"" + IL_017c: ldarg.0 + IL_017d: ldfld ""System.Collections.Generic.IEnumerator> C.d__0.<>s__8"" + IL_0182: callvirt ""bool System.Collections.IEnumerator.MoveNext()"" + IL_0187: brtrue IL_00e2 + IL_018c: ldarg.0 + IL_018d: call ""void C.d__0.<>m__Finally7()"" + IL_0192: nop + IL_0193: ldarg.0 + IL_0194: ldnull + IL_0195: stfld ""System.Collections.Generic.IEnumerator> C.d__0.<>s__8"" + IL_019a: ldarg.0 + IL_019b: ldflda ""System.ValueTuple C.d__0.5__7"" + IL_01a0: initobj ""System.ValueTuple"" + IL_01a6: ldarg.0 + IL_01a7: ldfld ""System.Collections.Generic.IEnumerator> C.d__0.<>s__6"" + IL_01ac: callvirt ""bool System.Collections.IEnumerator.MoveNext()"" + IL_01b1: brtrue IL_00b3 + IL_01b6: ldarg.0 + IL_01b7: call ""void C.d__0.<>m__Finally6()"" + IL_01bc: nop + IL_01bd: ldarg.0 + IL_01be: ldnull + IL_01bf: stfld ""System.Collections.Generic.IEnumerator> C.d__0.<>s__6"" + IL_01c4: ldarg.0 + IL_01c5: call ""void C.d__0.<>m__Finally5()"" + IL_01ca: nop + IL_01cb: ldarg.0 + IL_01cc: call ""void C.d__0.<>m__Finally4()"" + IL_01d1: nop + IL_01d2: ldarg.0 + IL_01d3: ldnull + IL_01d4: stfld ""System.IDisposable C.d__0.5__4"" + IL_01d9: ldarg.0 + IL_01da: ldnull + IL_01db: stfld ""System.IDisposable C.d__0.5__5"" + IL_01e0: ldarg.0 + IL_01e1: call ""void C.d__0.<>m__Finally3()"" + IL_01e6: nop + IL_01e7: ldarg.0 + IL_01e8: ldnull + IL_01e9: stfld ""System.IDisposable C.d__0.<>s__3"" + IL_01ee: ldc.i4.0 + IL_01ef: stloc.0 + IL_01f0: br.s IL_01f2 + IL_01f2: ldarg.0 + IL_01f3: call ""void C.d__0.<>m__Finally2()"" + IL_01f8: nop + IL_01f9: br.s IL_01fb + IL_01fb: ldarg.0 + IL_01fc: call ""void C.d__0.<>m__Finally1()"" + IL_0201: nop + IL_0202: leave.s IL_020c + } + fault + { + IL_0204: ldarg.0 + IL_0205: call ""void C.d__0.Dispose()"" + IL_020a: nop + IL_020b: endfinally + } + IL_020c: ldloc.0 + IL_020d: ret }"); - } - } } [Fact] - public void UpdateIterator_UserDefinedVariables_ChangeVariableType() + public void UpdateAsyncEnumerable_AwaitAndYield_AddAndRemove() { - var source0 = @" -using System; + var source0 = MarkedSource(@" using System.Collections.Generic; +using System.Threading.Tasks; class C { - static IEnumerable F() + async IAsyncEnumerable F() { - var x = 1; - yield return 1; - Console.WriteLine(x); + yield return F1(); + await Task.FromResult(1); + End(); } -}"; - var source1 = @" -using System; + + static int F1() => 1; + static int F2() => 1; + static void End() { } +} +"); + var source1 = MarkedSource(@" using System.Collections.Generic; +using System.Threading.Tasks; class C { - static IEnumerable F() + async IAsyncEnumerable F() { - var x = 1.0; - yield return 2; - Console.WriteLine(x); + yield return F2(); + await Task.FromResult(2); + yield return F1(); + await Task.FromResult(1); + End(); } -}"; - var compilation0 = CreateCompilationWithMscorlib45(source0, options: ComSafeDebugDll); - var compilation1 = compilation0.WithSource(source1); - - var v0 = CompileAndVerify(compilation0); - var symReader = v0.CreateSymReader(); - - using (var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData)) - { - var method0 = compilation0.GetMember("C.F"); - var method1 = compilation1.GetMember("C.F"); - - var generation0 = EmitBaseline.CreateInitialBaseline(md0, symReader.GetEncMethodDebugInfo); - var diff1 = compilation1.EmitDifference( - generation0, - ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1, GetEquivalentNodesMap(method1, method0), preserveLocalVariables: true))); - - // Verify delta metadata contains expected rows. - using (var md1 = diff1.GetMetadata()) - { - // 1 field def added & 3 methods updated - CheckEncLogDefinitions(md1.Reader, - Row(3, TableIndex.StandAloneSig, EditAndContinueOperation.Default), - Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), - Row(5, TableIndex.Field, EditAndContinueOperation.Default), - Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(1, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); - diff1.VerifyIL("C.d__0.System.Collections.IEnumerator.MoveNext", @" -{ - // Code size 84 (0x54) - .maxstack 2 - .locals init (int V_0) - IL_0000: ldarg.0 - IL_0001: ldfld ""int C.d__0.<>1__state"" - IL_0006: stloc.0 - IL_0007: ldloc.0 - IL_0008: brfalse.s IL_0012 - IL_000a: br.s IL_000c - IL_000c: ldloc.0 - IL_000d: ldc.i4.1 - IL_000e: beq.s IL_0014 - IL_0010: br.s IL_0016 - IL_0012: br.s IL_0018 - IL_0014: br.s IL_003f - IL_0016: ldc.i4.0 - IL_0017: ret - IL_0018: ldarg.0 - IL_0019: ldc.i4.m1 - IL_001a: stfld ""int C.d__0.<>1__state"" - IL_001f: nop - IL_0020: ldarg.0 - IL_0021: ldc.r8 1 - IL_002a: stfld ""double C.d__0.5__2"" - IL_002f: ldarg.0 - IL_0030: ldc.i4.2 - IL_0031: stfld ""int C.d__0.<>2__current"" - IL_0036: ldarg.0 - IL_0037: ldc.i4.1 - IL_0038: stfld ""int C.d__0.<>1__state"" - IL_003d: ldc.i4.1 - IL_003e: ret - IL_003f: ldarg.0 - IL_0040: ldc.i4.m1 - IL_0041: stfld ""int C.d__0.<>1__state"" - IL_0046: ldarg.0 - IL_0047: ldfld ""double C.d__0.5__2"" - IL_004c: call ""void System.Console.WriteLine(double)"" - IL_0051: nop - IL_0052: ldc.i4.0 - IL_0053: ret + static int F1() => 1; + static int F2() => 1; + static void End() { } }"); - } - } - } - - [Fact] - public void UpdateIterator_SynthesizedVariables_ChangeVariableType() - { - var source0 = @" -using System; + var source2 = MarkedSource(@" using System.Collections.Generic; +using System.Threading.Tasks; class C { - static IEnumerable F() + async IAsyncEnumerable F() { - foreach (object item in new[] { 1 }) { yield return 1; } + yield return F2(); + await Task.FromResult(2); + await Task.FromResult(1); + End(); } -}"; - var source1 = @" -using System; + + static int F1() => 1; + static int F2() => 1; + static void End() { } +}"); + var source3 = MarkedSource(@" using System.Collections.Generic; +using System.Threading.Tasks; class C { - static IEnumerable F() + async IAsyncEnumerable F() { - foreach (object item in new[] { 1.0 }) { yield return 1; } + yield return F2(); + await Task.FromResult(1); + End(); } -}"; - // Rude edit but the compiler should handle it. - var compilation0 = CreateCompilationWithMscorlib45(source0, options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); - var compilation1 = compilation0.WithSource(source1); + static int F1() => 1; + static int F2() => 1; + static void End() { } +}"); + var asyncStreamsTree = Parse(AsyncStreamsTypes); + + var compilation0 = CreateCompilationWithTasksExtensions(new[] { source0.Tree, asyncStreamsTree }, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(new[] { source1.Tree, asyncStreamsTree }); + var compilation2 = compilation1.WithSource(new[] { source2.Tree, asyncStreamsTree }); + var compilation3 = compilation2.WithSource(new[] { source3.Tree, asyncStreamsTree }); + + var v0 = CompileAndVerify(compilation0); + v0.VerifyDiagnostics(); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); + var f2 = compilation2.GetMember("C.F"); + var f3 = compilation3.GetMember("C.F"); - var v0 = CompileAndVerify(compilation0, symbolValidator: module => - { - Assert.Equal(new[] - { - "<>1__state: int", - "<>2__current: int", - "<>l__initialThreadId: int", - "<>s__1: int[]", - "<>s__2: int", - "5__3: object" - }, module.GetFieldNamesAndTypes("C.d__0")); - }); + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); - var symReader = v0.CreateSymReader(); + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); - using (var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData)) - { - var method0 = compilation0.GetMember("C.F"); - var method1 = compilation1.GetMember("C.F"); + var diff2 = compilation2.EmitDifference( + diff1.NextGeneration, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, f1, f2, GetSyntaxMapFromMarkers(source1, source2), preserveLocalVariables: true))); - var generation0 = EmitBaseline.CreateInitialBaseline(md0, symReader.GetEncMethodDebugInfo); - var diff1 = compilation1.EmitDifference( - generation0, - ImmutableArray.Create(SemanticEdit.Create(SemanticEditKind.Update, method0, method1, GetSyntaxMapByKind(method0, SyntaxKind.ForEachStatement), preserveLocalVariables: true))); + var diff3 = compilation3.EmitDifference( + diff2.NextGeneration, + ImmutableArray.Create( + SemanticEdit.Create(SemanticEditKind.Update, f2, f3, GetSyntaxMapFromMarkers(source2, source3), preserveLocalVariables: true))); - // Verify delta metadata contains expected rows. - using (var md1 = diff1.GetMetadata()) - { - // 1 field def added & 3 methods updated - CheckEncLogDefinitions(md1.Reader, - Row(3, TableIndex.StandAloneSig, EditAndContinueOperation.Default), - Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), - Row(7, TableIndex.Field, EditAndContinueOperation.Default), - Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(1, TableIndex.CustomAttribute, EditAndContinueOperation.Default), - Row(7, TableIndex.CustomAttribute, EditAndContinueOperation.Default)); + v0.VerifyPdb("C.F", @" + + + + + + + + + + + + + + + + +"); - diff1.VerifyIL("C.d__0.System.Collections.IEnumerator.MoveNext", @" + diff1.VerifyIL("C.d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" { - // Code size 161 (0xa1) - .maxstack 5 - .locals init (int V_0) + // Code size 484 (0x1e4) + .maxstack 3 + .locals init (int V_0, + System.Runtime.CompilerServices.TaskAwaiter V_1, + C.d__0 V_2, + System.Runtime.CompilerServices.TaskAwaiter V_3, + System.Exception V_4) IL_0000: ldarg.0 IL_0001: ldfld ""int C.d__0.<>1__state"" IL_0006: stloc.0 - IL_0007: ldloc.0 - IL_0008: brfalse.s IL_0012 - IL_000a: br.s IL_000c - IL_000c: ldloc.0 - IL_000d: ldc.i4.1 - IL_000e: beq.s IL_0014 - IL_0010: br.s IL_0016 - IL_0012: br.s IL_0018 - IL_0014: br.s IL_006b - IL_0016: ldc.i4.0 - IL_0017: ret - IL_0018: ldarg.0 - IL_0019: ldc.i4.m1 - IL_001a: stfld ""int C.d__0.<>1__state"" - IL_001f: nop - IL_0020: nop - IL_0021: ldarg.0 - IL_0022: ldc.i4.1 - IL_0023: newarr ""double"" - IL_0028: dup - IL_0029: ldc.i4.0 - IL_002a: ldc.r8 1 - IL_0033: stelem.r8 - IL_0034: stfld ""double[] C.d__0.<>s__4"" - IL_0039: ldarg.0 - IL_003a: ldc.i4.0 - IL_003b: stfld ""int C.d__0.<>s__2"" - IL_0040: br.s IL_0088 - IL_0042: ldarg.0 - IL_0043: ldarg.0 - IL_0044: ldfld ""double[] C.d__0.<>s__4"" - IL_0049: ldarg.0 - IL_004a: ldfld ""int C.d__0.<>s__2"" - IL_004f: ldelem.r8 - IL_0050: box ""double"" - IL_0055: stfld ""object C.d__0.5__3"" - IL_005a: nop - IL_005b: ldarg.0 - IL_005c: ldc.i4.1 - IL_005d: stfld ""int C.d__0.<>2__current"" - IL_0062: ldarg.0 - IL_0063: ldc.i4.1 - IL_0064: stfld ""int C.d__0.<>1__state"" - IL_0069: ldc.i4.1 - IL_006a: ret - IL_006b: ldarg.0 - IL_006c: ldc.i4.m1 - IL_006d: stfld ""int C.d__0.<>1__state"" - IL_0072: nop - IL_0073: ldarg.0 - IL_0074: ldnull - IL_0075: stfld ""object C.d__0.5__3"" - IL_007a: ldarg.0 - IL_007b: ldarg.0 - IL_007c: ldfld ""int C.d__0.<>s__2"" - IL_0081: ldc.i4.1 - IL_0082: add - IL_0083: stfld ""int C.d__0.<>s__2"" - IL_0088: ldarg.0 - IL_0089: ldfld ""int C.d__0.<>s__2"" - IL_008e: ldarg.0 - IL_008f: ldfld ""double[] C.d__0.<>s__4"" - IL_0094: ldlen - IL_0095: conv.i4 - IL_0096: blt.s IL_0042 - IL_0098: ldarg.0 - IL_0099: ldnull - IL_009a: stfld ""double[] C.d__0.<>s__4"" - IL_009f: ldc.i4.0 - IL_00a0: ret + .try + { + IL_0007: ldloc.0 + IL_0008: ldc.i4.s -5 + IL_000a: sub + IL_000b: switch ( + IL_002e, + IL_0030, + IL_0035, + IL_0041, + IL_0041, + IL_0037, + IL_003c) + IL_002c: br.s IL_0041 + IL_002e: br.s IL_0072 + IL_0030: br IL_0102 + IL_0035: br.s IL_0041 + IL_0037: br IL_0154 + IL_003c: br IL_00c4 + IL_0041: ldarg.0 + IL_0042: ldfld ""bool C.d__0.<>w__disposeMode"" + IL_0047: brfalse.s IL_004e + IL_0049: leave IL_01ad + IL_004e: ldarg.0 + IL_004f: ldc.i4.m1 + IL_0050: dup + IL_0051: stloc.0 + IL_0052: stfld ""int C.d__0.<>1__state"" + IL_0057: nop + IL_0058: ldarg.0 + IL_0059: call ""int C.F2()"" + IL_005e: stfld ""int C.d__0.<>2__current"" + IL_0063: ldarg.0 + IL_0064: ldc.i4.s -5 + IL_0066: dup + IL_0067: stloc.0 + IL_0068: stfld ""int C.d__0.<>1__state"" + IL_006d: leave IL_01d6 + IL_0072: ldarg.0 + IL_0073: ldc.i4.m1 + IL_0074: dup + IL_0075: stloc.0 + IL_0076: stfld ""int C.d__0.<>1__state"" + IL_007b: ldarg.0 + IL_007c: ldfld ""bool C.d__0.<>w__disposeMode"" + IL_0081: brfalse.s IL_0088 + IL_0083: leave IL_01ad + IL_0088: ldc.i4.2 + IL_0089: call ""System.Threading.Tasks.Task System.Threading.Tasks.Task.FromResult(int)"" + IL_008e: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0093: stloc.1 + IL_0094: ldloca.s V_1 + IL_0096: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_009b: brtrue.s IL_00e0 + IL_009d: ldarg.0 + IL_009e: ldc.i4.1 + IL_009f: dup + IL_00a0: stloc.0 + IL_00a1: stfld ""int C.d__0.<>1__state"" + IL_00a6: ldarg.0 + IL_00a7: ldloc.1 + IL_00a8: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_00ad: ldarg.0 + IL_00ae: stloc.2 + IL_00af: ldarg.0 + IL_00b0: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_00b5: ldloca.s V_1 + IL_00b7: ldloca.s V_2 + IL_00b9: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.AwaitUnsafeOnCompleted, C.d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__0)"" + IL_00be: nop + IL_00bf: leave IL_01e3 + IL_00c4: ldarg.0 + IL_00c5: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_00ca: stloc.1 + IL_00cb: ldarg.0 + IL_00cc: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_00d1: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_00d7: ldarg.0 + IL_00d8: ldc.i4.m1 + IL_00d9: dup + IL_00da: stloc.0 + IL_00db: stfld ""int C.d__0.<>1__state"" + IL_00e0: ldloca.s V_1 + IL_00e2: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_00e7: pop + IL_00e8: ldarg.0 + IL_00e9: call ""int C.F1()"" + IL_00ee: stfld ""int C.d__0.<>2__current"" + IL_00f3: ldarg.0 + IL_00f4: ldc.i4.s -4 + IL_00f6: dup + IL_00f7: stloc.0 + IL_00f8: stfld ""int C.d__0.<>1__state"" + IL_00fd: leave IL_01d6 + IL_0102: ldarg.0 + IL_0103: ldc.i4.m1 + IL_0104: dup + IL_0105: stloc.0 + IL_0106: stfld ""int C.d__0.<>1__state"" + IL_010b: ldarg.0 + IL_010c: ldfld ""bool C.d__0.<>w__disposeMode"" + IL_0111: brfalse.s IL_0118 + IL_0113: leave IL_01ad + IL_0118: ldc.i4.1 + IL_0119: call ""System.Threading.Tasks.Task System.Threading.Tasks.Task.FromResult(int)"" + IL_011e: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0123: stloc.3 + IL_0124: ldloca.s V_3 + IL_0126: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_012b: brtrue.s IL_0170 + IL_012d: ldarg.0 + IL_012e: ldc.i4.0 + IL_012f: dup + IL_0130: stloc.0 + IL_0131: stfld ""int C.d__0.<>1__state"" + IL_0136: ldarg.0 + IL_0137: ldloc.3 + IL_0138: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_013d: ldarg.0 + IL_013e: stloc.2 + IL_013f: ldarg.0 + IL_0140: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_0145: ldloca.s V_3 + IL_0147: ldloca.s V_2 + IL_0149: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.AwaitUnsafeOnCompleted, C.d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__0)"" + IL_014e: nop + IL_014f: leave IL_01e3 + IL_0154: ldarg.0 + IL_0155: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_015a: stloc.3 + IL_015b: ldarg.0 + IL_015c: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_0161: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0167: ldarg.0 + IL_0168: ldc.i4.m1 + IL_0169: dup + IL_016a: stloc.0 + IL_016b: stfld ""int C.d__0.<>1__state"" + IL_0170: ldloca.s V_3 + IL_0172: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0177: pop + IL_0178: call ""void C.End()"" + IL_017d: nop + IL_017e: leave.s IL_01ad + } + catch System.Exception + { + IL_0180: stloc.s V_4 + IL_0182: ldarg.0 + IL_0183: ldc.i4.s -2 + IL_0185: stfld ""int C.d__0.<>1__state"" + IL_018a: ldarg.0 + IL_018b: ldc.i4.0 + IL_018c: stfld ""int C.d__0.<>2__current"" + IL_0191: ldarg.0 + IL_0192: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_0197: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_019c: nop + IL_019d: ldarg.0 + IL_019e: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_01a3: ldloc.s V_4 + IL_01a5: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)"" + IL_01aa: nop + IL_01ab: leave.s IL_01e3 + } + IL_01ad: ldarg.0 + IL_01ae: ldc.i4.s -2 + IL_01b0: stfld ""int C.d__0.<>1__state"" + IL_01b5: ldarg.0 + IL_01b6: ldc.i4.0 + IL_01b7: stfld ""int C.d__0.<>2__current"" + IL_01bc: ldarg.0 + IL_01bd: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_01c2: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_01c7: nop + IL_01c8: ldarg.0 + IL_01c9: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_01ce: ldc.i4.0 + IL_01cf: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_01d4: nop + IL_01d5: ret + IL_01d6: ldarg.0 + IL_01d7: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_01dc: ldc.i4.1 + IL_01dd: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_01e2: nop + IL_01e3: ret +} +"); + + diff2.VerifyIL("C.d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" +{ + // Code size 447 (0x1bf) + .maxstack 3 + .locals init (int V_0, + System.Runtime.CompilerServices.TaskAwaiter V_1, + C.d__0 V_2, + System.Runtime.CompilerServices.TaskAwaiter V_3, + System.Exception V_4) + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__0.<>1__state"" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: ldc.i4.s -5 + IL_000a: sub + IL_000b: switch ( + IL_002e, + IL_003c, + IL_0030, + IL_003c, + IL_003c, + IL_0032, + IL_0037) + IL_002c: br.s IL_003c + IL_002e: br.s IL_007d + IL_0030: br.s IL_004c + IL_0032: br IL_012f + IL_0037: br IL_00cf + IL_003c: ldloc.0 + IL_003d: ldc.i4.s -4 + IL_003f: bgt.s IL_004c + IL_0041: ldstr """ + CodeAnalysisResources.EncCannotResumeSuspendedIteratorMethod + @""" + IL_0046: newobj ""System.InvalidOperationException..ctor(string)"" + IL_004b: throw + IL_004c: ldarg.0 + IL_004d: ldfld ""bool C.d__0.<>w__disposeMode"" + IL_0052: brfalse.s IL_0059 + IL_0054: leave IL_0188 + IL_0059: ldarg.0 + IL_005a: ldc.i4.m1 + IL_005b: dup + IL_005c: stloc.0 + IL_005d: stfld ""int C.d__0.<>1__state"" + IL_0062: nop + IL_0063: ldarg.0 + IL_0064: call ""int C.F2()"" + IL_0069: stfld ""int C.d__0.<>2__current"" + IL_006e: ldarg.0 + IL_006f: ldc.i4.s -5 + IL_0071: dup + IL_0072: stloc.0 + IL_0073: stfld ""int C.d__0.<>1__state"" + IL_0078: leave IL_01b1 + IL_007d: ldarg.0 + IL_007e: ldc.i4.m1 + IL_007f: dup + IL_0080: stloc.0 + IL_0081: stfld ""int C.d__0.<>1__state"" + IL_0086: ldarg.0 + IL_0087: ldfld ""bool C.d__0.<>w__disposeMode"" + IL_008c: brfalse.s IL_0093 + IL_008e: leave IL_0188 + IL_0093: ldc.i4.2 + IL_0094: call ""System.Threading.Tasks.Task System.Threading.Tasks.Task.FromResult(int)"" + IL_0099: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_009e: stloc.1 + IL_009f: ldloca.s V_1 + IL_00a1: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_00a6: brtrue.s IL_00eb + IL_00a8: ldarg.0 + IL_00a9: ldc.i4.1 + IL_00aa: dup + IL_00ab: stloc.0 + IL_00ac: stfld ""int C.d__0.<>1__state"" + IL_00b1: ldarg.0 + IL_00b2: ldloc.1 + IL_00b3: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_00b8: ldarg.0 + IL_00b9: stloc.2 + IL_00ba: ldarg.0 + IL_00bb: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_00c0: ldloca.s V_1 + IL_00c2: ldloca.s V_2 + IL_00c4: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.AwaitUnsafeOnCompleted, C.d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__0)"" + IL_00c9: nop + IL_00ca: leave IL_01be + IL_00cf: ldarg.0 + IL_00d0: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_00d5: stloc.1 + IL_00d6: ldarg.0 + IL_00d7: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_00dc: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_00e2: ldarg.0 + IL_00e3: ldc.i4.m1 + IL_00e4: dup + IL_00e5: stloc.0 + IL_00e6: stfld ""int C.d__0.<>1__state"" + IL_00eb: ldloca.s V_1 + IL_00ed: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_00f2: pop + IL_00f3: ldc.i4.1 + IL_00f4: call ""System.Threading.Tasks.Task System.Threading.Tasks.Task.FromResult(int)"" + IL_00f9: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_00fe: stloc.3 + IL_00ff: ldloca.s V_3 + IL_0101: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_0106: brtrue.s IL_014b + IL_0108: ldarg.0 + IL_0109: ldc.i4.0 + IL_010a: dup + IL_010b: stloc.0 + IL_010c: stfld ""int C.d__0.<>1__state"" + IL_0111: ldarg.0 + IL_0112: ldloc.3 + IL_0113: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_0118: ldarg.0 + IL_0119: stloc.2 + IL_011a: ldarg.0 + IL_011b: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_0120: ldloca.s V_3 + IL_0122: ldloca.s V_2 + IL_0124: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.AwaitUnsafeOnCompleted, C.d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__0)"" + IL_0129: nop + IL_012a: leave IL_01be + IL_012f: ldarg.0 + IL_0130: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_0135: stloc.3 + IL_0136: ldarg.0 + IL_0137: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_013c: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_0142: ldarg.0 + IL_0143: ldc.i4.m1 + IL_0144: dup + IL_0145: stloc.0 + IL_0146: stfld ""int C.d__0.<>1__state"" + IL_014b: ldloca.s V_3 + IL_014d: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_0152: pop + IL_0153: call ""void C.End()"" + IL_0158: nop + IL_0159: leave.s IL_0188 + } + catch System.Exception + { + IL_015b: stloc.s V_4 + IL_015d: ldarg.0 + IL_015e: ldc.i4.s -2 + IL_0160: stfld ""int C.d__0.<>1__state"" + IL_0165: ldarg.0 + IL_0166: ldc.i4.0 + IL_0167: stfld ""int C.d__0.<>2__current"" + IL_016c: ldarg.0 + IL_016d: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_0172: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_0177: nop + IL_0178: ldarg.0 + IL_0179: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_017e: ldloc.s V_4 + IL_0180: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)"" + IL_0185: nop + IL_0186: leave.s IL_01be + } + IL_0188: ldarg.0 + IL_0189: ldc.i4.s -2 + IL_018b: stfld ""int C.d__0.<>1__state"" + IL_0190: ldarg.0 + IL_0191: ldc.i4.0 + IL_0192: stfld ""int C.d__0.<>2__current"" + IL_0197: ldarg.0 + IL_0198: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_019d: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_01a2: nop + IL_01a3: ldarg.0 + IL_01a4: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_01a9: ldc.i4.0 + IL_01aa: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_01af: nop + IL_01b0: ret + IL_01b1: ldarg.0 + IL_01b2: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_01b7: ldc.i4.1 + IL_01b8: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_01bd: nop + IL_01be: ret +}"); + diff3.VerifyIL("C.d__0.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext", @" +{ + // Code size 339 (0x153) + .maxstack 3 + .locals init (int V_0, + System.Runtime.CompilerServices.TaskAwaiter V_1, + C.d__0 V_2, + System.Exception V_3) + IL_0000: ldarg.0 + IL_0001: ldfld ""int C.d__0.<>1__state"" + IL_0006: stloc.0 + .try + { + IL_0007: ldloc.0 + IL_0008: ldc.i4.s -5 + IL_000a: beq.s IL_001a + IL_000c: br.s IL_000e + IL_000e: ldloc.0 + IL_000f: ldc.i4.s -3 + IL_0011: beq.s IL_001c + IL_0013: br.s IL_0015 + IL_0015: ldloc.0 + IL_0016: brfalse.s IL_001e + IL_0018: br.s IL_0023 + IL_001a: br.s IL_0073 + IL_001c: br.s IL_0042 + IL_001e: br IL_00c5 + + IL_0023: ldloc.0 + IL_0024: ldc.i4.0 + IL_0025: blt.s IL_0032 + IL_0027: ldstr """ + CodeAnalysisResources.EncCannotResumeSuspendedAsyncMethod + @""" + IL_002c: newobj ""System.InvalidOperationException..ctor(string)"" + IL_0031: throw + + IL_0032: ldloc.0 + IL_0033: ldc.i4.s -4 + IL_0035: bgt.s IL_0042 + IL_0037: ldstr """ + CodeAnalysisResources.EncCannotResumeSuspendedIteratorMethod + @""" + IL_003c: newobj ""System.InvalidOperationException..ctor(string)"" + IL_0041: throw + + IL_0042: ldarg.0 + IL_0043: ldfld ""bool C.d__0.<>w__disposeMode"" + IL_0048: brfalse.s IL_004f + IL_004a: leave IL_011c + + IL_004f: ldarg.0 + IL_0050: ldc.i4.m1 + IL_0051: dup + IL_0052: stloc.0 + IL_0053: stfld ""int C.d__0.<>1__state"" + IL_0058: nop + IL_0059: ldarg.0 + IL_005a: call ""int C.F2()"" + IL_005f: stfld ""int C.d__0.<>2__current"" + IL_0064: ldarg.0 + IL_0065: ldc.i4.s -5 + IL_0067: dup + IL_0068: stloc.0 + IL_0069: stfld ""int C.d__0.<>1__state"" + IL_006e: leave IL_0145 + + IL_0073: ldarg.0 + IL_0074: ldc.i4.m1 + IL_0075: dup + IL_0076: stloc.0 + IL_0077: stfld ""int C.d__0.<>1__state"" + IL_007c: ldarg.0 + IL_007d: ldfld ""bool C.d__0.<>w__disposeMode"" + IL_0082: brfalse.s IL_0089 + IL_0084: leave IL_011c + + IL_0089: ldc.i4.1 + IL_008a: call ""System.Threading.Tasks.Task System.Threading.Tasks.Task.FromResult(int)"" + IL_008f: callvirt ""System.Runtime.CompilerServices.TaskAwaiter System.Threading.Tasks.Task.GetAwaiter()"" + IL_0094: stloc.1 + IL_0095: ldloca.s V_1 + IL_0097: call ""bool System.Runtime.CompilerServices.TaskAwaiter.IsCompleted.get"" + IL_009c: brtrue.s IL_00e1 + + IL_009e: ldarg.0 + IL_009f: ldc.i4.0 + IL_00a0: dup + IL_00a1: stloc.0 + IL_00a2: stfld ""int C.d__0.<>1__state"" + IL_00a7: ldarg.0 + IL_00a8: ldloc.1 + IL_00a9: stfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_00ae: ldarg.0 + IL_00af: stloc.2 + IL_00b0: ldarg.0 + IL_00b1: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_00b6: ldloca.s V_1 + IL_00b8: ldloca.s V_2 + IL_00ba: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.AwaitUnsafeOnCompleted, C.d__0>(ref System.Runtime.CompilerServices.TaskAwaiter, ref C.d__0)"" + IL_00bf: nop + IL_00c0: leave IL_0152 + + IL_00c5: ldarg.0 + IL_00c6: ldfld ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_00cb: stloc.1 + IL_00cc: ldarg.0 + IL_00cd: ldflda ""System.Runtime.CompilerServices.TaskAwaiter C.d__0.<>u__1"" + IL_00d2: initobj ""System.Runtime.CompilerServices.TaskAwaiter"" + IL_00d8: ldarg.0 + IL_00d9: ldc.i4.m1 + IL_00da: dup + IL_00db: stloc.0 + IL_00dc: stfld ""int C.d__0.<>1__state"" + + IL_00e1: ldloca.s V_1 + IL_00e3: call ""int System.Runtime.CompilerServices.TaskAwaiter.GetResult()"" + IL_00e8: pop + IL_00e9: call ""void C.End()"" + IL_00ee: nop + IL_00ef: leave.s IL_011c + } + catch System.Exception + { + IL_00f1: stloc.3 + IL_00f2: ldarg.0 + IL_00f3: ldc.i4.s -2 + IL_00f5: stfld ""int C.d__0.<>1__state"" + IL_00fa: ldarg.0 + IL_00fb: ldc.i4.0 + IL_00fc: stfld ""int C.d__0.<>2__current"" + IL_0101: ldarg.0 + IL_0102: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_0107: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_010c: nop + IL_010d: ldarg.0 + IL_010e: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_0113: ldloc.3 + IL_0114: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetException(System.Exception)"" + IL_0119: nop + IL_011a: leave.s IL_0152 + } + IL_011c: ldarg.0 + IL_011d: ldc.i4.s -2 + IL_011f: stfld ""int C.d__0.<>1__state"" + IL_0124: ldarg.0 + IL_0125: ldc.i4.0 + IL_0126: stfld ""int C.d__0.<>2__current"" + IL_012b: ldarg.0 + IL_012c: ldflda ""System.Runtime.CompilerServices.AsyncIteratorMethodBuilder C.d__0.<>t__builder"" + IL_0131: call ""void System.Runtime.CompilerServices.AsyncIteratorMethodBuilder.Complete()"" + IL_0136: nop + IL_0137: ldarg.0 + IL_0138: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_013d: ldc.i4.0 + IL_013e: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_0143: nop + IL_0144: ret + + IL_0145: ldarg.0 + IL_0146: ldflda ""System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore C.d__0.<>v__promiseOfValueOrEnd"" + IL_014b: ldc.i4.1 + IL_014c: call ""void System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore.SetResult(bool)"" + IL_0151: nop + IL_0152: ret }"); - } - } } [Fact] public void HoistedVariables_MultipleGenerations() { - var source0 = @" + var source0 = MarkedSource(@" using System.Threading.Tasks; class C { static async Task F() // testing type changes G0 -> G1, G1 -> G2 { - bool a1 = true; - int a2 = 3; - await Task.Delay(0); + bool a1 = true; + int a2 = 3; + await Task.Delay(0); return 1; } static async Task G() // testing G1 -> G3 { - C c = new C(); - bool a1 = true; - await Task.Delay(0); + C c = new C(); + bool a1 = true; + await Task.Delay(0); return 1; } static async Task H() // testing G0 -> G3 { - C c = new C(); - bool a1 = true; - await Task.Delay(0); + C c = new C(); + bool a1 = true; + await Task.Delay(0); return 1; } -}"; - var source1 = @" +}"); + var source1 = MarkedSource(@" using System.Threading.Tasks; class C { static async Task F() // updated { - C a1 = new C(); - int a2 = 3; - await Task.Delay(0); + C a1 = new C(); + int a2 = 3; + await Task.Delay(0); return 1; } static async Task G() // updated { - C c = new C(); - bool a1 = true; - await Task.Delay(0); + C c = new C(); + bool a1 = true; + await Task.Delay(0); return 2; } static async Task H() { - C c = new C(); - bool a1 = true; - await Task.Delay(0); + C c = new C(); + bool a1 = true; + await Task.Delay(0); return 1; } -}"; - var source2 = @" +}"); + var source2 = MarkedSource(@" using System.Threading.Tasks; class C { static async Task F() // updated { - bool a1 = true; - C a2 = new C(); - await Task.Delay(0); + bool a1 = true; + C a2 = new C(); + await Task.Delay(0); return 1; } static async Task G() { - C c = new C(); - bool a1 = true; - await Task.Delay(0); + C c = new C(); + bool a1 = true; + await Task.Delay(0); return 2; } static async Task H() { - C c = new C(); - bool a1 = true; - await Task.Delay(0); + C c = new C(); + bool a1 = true; + await Task.Delay(0); return 1; } -}"; - var source3 = @" +}"); + var source3 = MarkedSource(@" using System.Threading.Tasks; class C { static async Task F() { - bool a1 = true; - C a2 = new C(); - await Task.Delay(0); + bool a1 = true; + C a2 = new C(); + await Task.Delay(0); return 1; } static async Task G() // updated { - C c = new C(); - C a1 = new C(); - await Task.Delay(0); + C c = new C(); + C a1 = new C(); + await Task.Delay(0); return 1; } static async Task H() // updated { - C c = new C(); - C a1 = new C(); - await Task.Delay(0); + C c = new C(); + C a1 = new C(); + await Task.Delay(0); return 1; } -}"; +}"); // Rude edit but the compiler should handle it. - var compilation0 = CreateCompilationWithMscorlib45(source0, options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); - var compilation1 = compilation0.WithSource(source1); - var compilation2 = compilation1.WithSource(source2); - var compilation3 = compilation2.WithSource(source3); + var compilation0 = CreateCompilationWithMscorlib45(source0.Tree, options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + var compilation1 = compilation0.WithSource(source1.Tree); + var compilation2 = compilation1.WithSource(source2.Tree); + var compilation3 = compilation2.WithSource(source3.Tree); var f0 = compilation0.GetMember("C.F"); var f1 = compilation1.GetMember("C.F"); @@ -1837,34 +6132,36 @@ static async Task H() // updated }); var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); - + var syntaxMap1 = GetSyntaxMapFromMarkers(source0, source1); var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); var diff1 = compilation1.EmitDifference( generation0, ImmutableArray.Create( - SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetEquivalentNodesMap(f1, f0), preserveLocalVariables: true), - SemanticEdit.Create(SemanticEditKind.Update, g0, g1, GetEquivalentNodesMap(g1, g0), preserveLocalVariables: true))); + SemanticEdit.Create(SemanticEditKind.Update, f0, f1, syntaxMap1, preserveLocalVariables: true), + SemanticEdit.Create(SemanticEditKind.Update, g0, g1, syntaxMap1, preserveLocalVariables: true))); diff1.VerifySynthesizedMembers( "C: {d__0, d__1}", "C.d__0: {<>1__state, <>t__builder, 5__3, 5__2, <>u__1, MoveNext, SetStateMachine}", "C.d__1: {<>1__state, <>t__builder, 5__1, 5__2, <>u__1, MoveNext, SetStateMachine}"); + var syntaxMap2 = GetSyntaxMapFromMarkers(source1, source2); var diff2 = compilation2.EmitDifference( diff1.NextGeneration, ImmutableArray.Create( - SemanticEdit.Create(SemanticEditKind.Update, f1, f2, GetEquivalentNodesMap(f2, f1), preserveLocalVariables: true))); + SemanticEdit.Create(SemanticEditKind.Update, f1, f2, syntaxMap2, preserveLocalVariables: true))); diff2.VerifySynthesizedMembers( "C: {d__0, d__1}", "C.d__0: {<>1__state, <>t__builder, 5__4, 5__5, <>u__1, MoveNext, SetStateMachine, 5__3, 5__2}", "C.d__1: {<>1__state, <>t__builder, 5__1, 5__2, <>u__1, MoveNext, SetStateMachine}"); + var syntaxMap3 = GetSyntaxMapFromMarkers(source2, source3); var diff3 = compilation3.EmitDifference( diff2.NextGeneration, ImmutableArray.Create( - SemanticEdit.Create(SemanticEditKind.Update, g2, g3, GetEquivalentNodesMap(g3, g2), preserveLocalVariables: true), - SemanticEdit.Create(SemanticEditKind.Update, h2, h3, GetEquivalentNodesMap(h3, h2), preserveLocalVariables: true))); + SemanticEdit.Create(SemanticEditKind.Update, g2, g3, syntaxMap3, preserveLocalVariables: true), + SemanticEdit.Create(SemanticEditKind.Update, h2, h3, syntaxMap3, preserveLocalVariables: true))); diff3.VerifySynthesizedMembers( "C: {d__1, d__2, d__0}", @@ -2131,7 +6428,7 @@ class C public IEnumerable F() { dynamic x = 1; - yield return 1; + yield return 1; Console.WriteLine((int)x + <>); } } @@ -2438,7 +6735,7 @@ static async Task G() [MemberData(nameof(ExternalPdbFormats))] public void Awaiters_MultipleGenerations(DebugInformationFormat format) { - var source0 = @" + var source0 = MarkedSource(@" using System.Threading.Tasks; class C @@ -2449,24 +6746,24 @@ class C static async Task F() // testing type changes G0 -> G1, G1 -> G2 { - await A1(); - await A2(); + await A1(); + await A2(); return 1; } static async Task G() // testing G1 -> G3 { - await A1(); + await A1(); return 1; } static async Task H() // testing G0 -> G3 { - await A1(); + await A1(); return 1; } -}"; - var source1 = @" +}"); + var source1 = MarkedSource(@" using System.Threading.Tasks; class C @@ -2477,24 +6774,24 @@ class C static async Task F() // updated { - await A3(); - await A2(); + await A3(); + await A2(); return 1; } static async Task G() // updated { - await A1(); + await A1(); return 2; } static async Task H() { - await A1(); + await A1(); return 1; } -}"; - var source2 = @" +}"); + var source2 = MarkedSource(@" using System.Threading.Tasks; class C @@ -2505,24 +6802,24 @@ class C static async Task F() // updated { - await A1(); - await A3(); + await A1(); + await A3(); return 1; } static async Task G() { - await A1(); + await A1(); return 2; } static async Task H() { - await A1(); + await A1(); return 1; } -}"; - var source3 = @" +}"); + var source3 = MarkedSource(@" using System.Threading.Tasks; class C @@ -2533,30 +6830,30 @@ class C static async Task F() { - await A1(); - await A3(); + await A1(); + await A3(); return 1; } static async Task G() // updated { - await A3(); + await A3(); return 1; } static async Task H() // updated { - await A3(); + await A3(); return 1; } -}"; +}"); // Rude edit but the compiler should handle it. - var compilation0 = CreateCompilationWithMscorlib45(source0, options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All), assemblyName: "A"); - var compilation1 = compilation0.WithSource(source1); - var compilation2 = compilation1.WithSource(source2); - var compilation3 = compilation2.WithSource(source3); + var compilation0 = CreateCompilationWithMscorlib45(source0.Tree, options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All), assemblyName: "A"); + var compilation1 = compilation0.WithSource(source1.Tree); + var compilation2 = compilation1.WithSource(source2.Tree); + var compilation3 = compilation2.WithSource(source3.Tree); var f0 = compilation0.GetMember("C.F"); var f1 = compilation1.GetMember("C.F"); @@ -2587,32 +6884,35 @@ static async Task H() // updated var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + var syntaxMap1 = GetSyntaxMapFromMarkers(source0, source1); var diff1 = compilation1.EmitDifference( generation0, ImmutableArray.Create( - SemanticEdit.Create(SemanticEditKind.Update, f0, f1, GetSyntaxMapByKind(f0, SyntaxKind.Block), preserveLocalVariables: true), - SemanticEdit.Create(SemanticEditKind.Update, g0, g1, GetSyntaxMapByKind(g0, SyntaxKind.Block), preserveLocalVariables: true))); + SemanticEdit.Create(SemanticEditKind.Update, f0, f1, syntaxMap1, preserveLocalVariables: true), + SemanticEdit.Create(SemanticEditKind.Update, g0, g1, syntaxMap1, preserveLocalVariables: true))); diff1.VerifySynthesizedMembers( "C: {d__3, d__4}", "C.d__3: {<>1__state, <>t__builder, <>u__3, <>u__2, MoveNext, SetStateMachine}", "C.d__4: {<>1__state, <>t__builder, <>u__1, MoveNext, SetStateMachine}"); + var syntaxMap2 = GetSyntaxMapFromMarkers(source1, source2); var diff2 = compilation2.EmitDifference( diff1.NextGeneration, ImmutableArray.Create( - SemanticEdit.Create(SemanticEditKind.Update, f1, f2, GetSyntaxMapByKind(f1, SyntaxKind.Block), preserveLocalVariables: true))); + SemanticEdit.Create(SemanticEditKind.Update, f1, f2, syntaxMap2, preserveLocalVariables: true))); diff2.VerifySynthesizedMembers( "C: {d__3, d__4}", "C.d__3: {<>1__state, <>t__builder, <>u__4, <>u__3, MoveNext, SetStateMachine, <>u__2}", "C.d__4: {<>1__state, <>t__builder, <>u__1, MoveNext, SetStateMachine}"); + var syntaxMap3 = GetSyntaxMapFromMarkers(source2, source3); var diff3 = compilation3.EmitDifference( diff2.NextGeneration, ImmutableArray.Create( - SemanticEdit.Create(SemanticEditKind.Update, g2, g3, GetSyntaxMapByKind(g2, SyntaxKind.Block), preserveLocalVariables: true), - SemanticEdit.Create(SemanticEditKind.Update, h2, h3, GetSyntaxMapByKind(h2, SyntaxKind.Block), preserveLocalVariables: true))); + SemanticEdit.Create(SemanticEditKind.Update, g2, g3, syntaxMap3, preserveLocalVariables: true), + SemanticEdit.Create(SemanticEditKind.Update, h2, h3, syntaxMap3, preserveLocalVariables: true))); diff3.VerifySynthesizedMembers( "C: {d__4, d__5, d__3}", @@ -2641,9 +6941,9 @@ static async Task H() // updated public abstract bool TryGetPreviousLambda(SyntaxNode lambdaOrLambdaBodySyntax, bool isLambdaBody, out DebugId lambdaId); + + /// + /// State number to be used for next state of the state machine, + /// or if none of the previous versions of the method was a state machine with a increasing state + /// + /// True if the state number increases with progress, false if it decreases. + public abstract int? GetFirstUnusedStateMachineState(bool increasing); + + /// + /// For a given node associated with entering a state of a state machine in the new compilation, + /// returns the ordinal of the corresponding state in the previous version of the state machine. + /// + /// + /// True if there is a corresponding node in the previous code version that matches the given . + /// + /// + /// is an await expression, yield return statement, or try block syntax node. + /// + public abstract bool TryGetPreviousStateMachineState(SyntaxNode syntax, out int stateOrdinal); } } diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/AddedOrChangedMethodInfo.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/AddedOrChangedMethodInfo.cs index 2f98ba9d78668..98080deeaa1c7 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/AddedOrChangedMethodInfo.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/AddedOrChangedMethodInfo.cs @@ -24,6 +24,7 @@ internal readonly struct AddedOrChangedMethodInfo public readonly string? StateMachineTypeName; public readonly ImmutableArray StateMachineHoistedLocalSlotsOpt; public readonly ImmutableArray StateMachineAwaiterSlotsOpt; + public readonly StateMachineStatesDebugInfo StateMachineStates; public AddedOrChangedMethodInfo( DebugId methodId, @@ -32,17 +33,18 @@ public AddedOrChangedMethodInfo( ImmutableArray closureDebugInfo, string? stateMachineTypeName, ImmutableArray stateMachineHoistedLocalSlotsOpt, - ImmutableArray stateMachineAwaiterSlotsOpt) + ImmutableArray stateMachineAwaiterSlotsOpt, + StateMachineStatesDebugInfo stateMachineStates) { // An updated method will carry its id over, // an added method id has generation set to the current generation ordinal. Debug.Assert(methodId.Generation >= 0); // each state machine has to have awaiters: - Debug.Assert(stateMachineAwaiterSlotsOpt.IsDefault == (stateMachineTypeName == null)); + Debug.Assert(stateMachineAwaiterSlotsOpt.IsDefault == stateMachineTypeName is null); // a state machine might not have hoisted variables: - Debug.Assert(stateMachineHoistedLocalSlotsOpt.IsDefault || (stateMachineTypeName != null)); + Debug.Assert(stateMachineHoistedLocalSlotsOpt.IsDefault || stateMachineTypeName is not null); MethodId = methodId; Locals = locals; @@ -51,6 +53,7 @@ public AddedOrChangedMethodInfo( StateMachineTypeName = stateMachineTypeName; StateMachineHoistedLocalSlotsOpt = stateMachineHoistedLocalSlotsOpt; StateMachineAwaiterSlotsOpt = stateMachineAwaiterSlotsOpt; + StateMachineStates = stateMachineStates; } public AddedOrChangedMethodInfo MapTypes(SymbolMatcher map) @@ -63,7 +66,7 @@ public AddedOrChangedMethodInfo MapTypes(SymbolMatcher map) var mappedAwaiterSlots = StateMachineAwaiterSlotsOpt.IsDefault ? default : ImmutableArray.CreateRange(StateMachineAwaiterSlotsOpt, static (typeRef, map) => (typeRef is null) ? null : map.MapReference(typeRef), map); - return new AddedOrChangedMethodInfo(MethodId, mappedLocals, LambdaDebugInfo, ClosureDebugInfo, StateMachineTypeName, mappedHoistedLocalSlots, mappedAwaiterSlots); + return new AddedOrChangedMethodInfo(MethodId, mappedLocals, LambdaDebugInfo, ClosureDebugInfo, StateMachineTypeName, mappedHoistedLocalSlots, mappedAwaiterSlots, StateMachineStates); } private static EncLocalInfo MapLocalInfo(EncLocalInfo info, SymbolMatcher map) diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/DefinitionMap.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/DefinitionMap.cs index d5dca8be2c661..5eb02ef5dfe3c 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/DefinitionMap.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/DefinitionMap.cs @@ -143,7 +143,7 @@ protected abstract void GetStateMachineFieldMapFromMetadata( out int awaiterSlotCount); protected abstract ImmutableArray GetLocalSlotMapFromMetadata(StandaloneSignatureHandle handle, EditAndContinueMethodDebugInformation debugInfo); - protected abstract ITypeSymbolInternal? TryGetStateMachineType(EntityHandle methodHandle); + protected abstract ITypeSymbolInternal? TryGetStateMachineType(MethodDefinitionHandle methodHandle); internal VariableSlotAllocator? TryCreateVariableSlotAllocator(EmitBaseline baseline, Compilation compilation, IMethodSymbolInternal method, IMethodSymbolInternal topLevelMethod, DiagnosticBag diagnostics) { @@ -167,6 +167,9 @@ protected abstract void GetStateMachineFieldMapFromMetadata( IReadOnlyDictionary? awaiterMap = null; IReadOnlyDictionary>? lambdaMap = null; IReadOnlyDictionary? closureMap = null; + IReadOnlyDictionary? stateMachineStateMap = null; + int? firstUnusedIncreasingStateMachineState = null; + int? firstUnusedDecreasingStateMachineState = null; int hoistedLocalSlotCount = 0; int awaiterSlotCount = 0; @@ -182,6 +185,10 @@ protected abstract void GetStateMachineFieldMapFromMetadata( methodId = addedOrChangedMethod.MethodId; MakeLambdaAndClosureMaps(addedOrChangedMethod.LambdaDebugInfo, addedOrChangedMethod.ClosureDebugInfo, out lambdaMap, out closureMap); + MakeStateMachineStateMap(addedOrChangedMethod.StateMachineStates.States, out stateMachineStateMap); + + firstUnusedIncreasingStateMachineState = addedOrChangedMethod.StateMachineStates.FirstUnusedIncreasingStateMachineState; + firstUnusedDecreasingStateMachineState = addedOrChangedMethod.StateMachineStates.FirstUnusedDecreasingStateMachineState; if (addedOrChangedMethod.StateMachineTypeName != null) { @@ -241,6 +248,14 @@ protected abstract void GetStateMachineFieldMapFromMetadata( MakeLambdaAndClosureMaps(debugInfo.Lambdas, debugInfo.Closures, out lambdaMap, out closureMap); } + MakeStateMachineStateMap(debugInfo.StateMachineStates, out stateMachineStateMap); + + if (!debugInfo.StateMachineStates.IsDefaultOrEmpty) + { + firstUnusedIncreasingStateMachineState = debugInfo.StateMachineStates.Max(s => s.StateNumber) + 1; + firstUnusedDecreasingStateMachineState = debugInfo.StateMachineStates.Min(s => s.StateNumber) - 1; + } + ITypeSymbolInternal? stateMachineType = TryGetStateMachineType(previousHandle); if (stateMachineType != null) { @@ -317,6 +332,9 @@ protected abstract void GetStateMachineFieldMapFromMetadata( hoistedLocalMap, awaiterSlotCount, awaiterMap, + stateMachineStateMap, + firstUnusedIncreasingStateMachineState, + firstUnusedDecreasingStateMachineState, GetLambdaSyntaxFacts()); } @@ -356,6 +374,15 @@ private static void MakeLambdaAndClosureMaps( closureMap = closures; } + private static void MakeStateMachineStateMap( + ImmutableArray debugInfos, + out IReadOnlyDictionary? map) + { + map = debugInfos.IsDefault ? + null : + debugInfos.ToDictionary(entry => entry.SyntaxOffset, entry => entry.StateNumber); + } + private static void GetStateMachineFieldMapFromPreviousCompilation( ImmutableArray hoistedLocalSlots, ImmutableArray hoistedAwaiters, diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs index 4412a2bbbe4bf..42c215222b11f 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs @@ -759,7 +759,8 @@ protected override StandaloneSignatureHandle SerializeLocalVariablesSignature(IM body.ClosureDebugInfo, body.StateMachineTypeName, body.StateMachineHoistedLocalSlots, - body.StateMachineAwaiterSlots); + body.StateMachineAwaiterSlots, + body.StateMachineStatesDebugInfo); _addedOrChangedMethods.Add(body.MethodDefinition, info); diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/EncVariableSlotAllocator.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/EncVariableSlotAllocator.cs index 6bc4ceff225b0..841bd83956ca3 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/EncVariableSlotAllocator.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/EncVariableSlotAllocator.cs @@ -35,6 +35,9 @@ internal sealed class EncVariableSlotAllocator : VariableSlotAllocator private readonly IReadOnlyDictionary? _hoistedLocalSlots; private readonly int _awaiterCount; private readonly IReadOnlyDictionary? _awaiterMap; + private readonly IReadOnlyDictionary? _stateMachineStateMap; // SyntaxOffset -> State Ordinal + private readonly int? _firstUnusedDecreasingStateMachineState; + private readonly int? _firstUnusedIncreasingStateMachineState; // closures: private readonly IReadOnlyDictionary>? _lambdaMap; // SyntaxOffset -> (Lambda Id, Closure Ordinal) @@ -55,6 +58,9 @@ public EncVariableSlotAllocator( IReadOnlyDictionary? hoistedLocalSlots, int awaiterCount, IReadOnlyDictionary? awaiterMap, + IReadOnlyDictionary? stateMachineStateMap, + int? firstUnusedIncreasingStateMachineState, + int? firstUnusedDecreasingStateMachineState, LambdaSyntaxFacts lambdaSyntaxFacts) { Debug.Assert(!previousLocals.IsDefault); @@ -69,9 +75,12 @@ public EncVariableSlotAllocator( _stateMachineTypeName = stateMachineTypeName; _awaiterCount = awaiterCount; _awaiterMap = awaiterMap; + _stateMachineStateMap = stateMachineStateMap; _lambdaMap = lambdaMap; _closureMap = closureMap; _lambdaSyntaxFacts = lambdaSyntaxFacts; + _firstUnusedIncreasingStateMachineState = firstUnusedIncreasingStateMachineState; + _firstUnusedDecreasingStateMachineState = firstUnusedDecreasingStateMachineState; // Create a map from local info to slot. var previousLocalInfoToSlot = new Dictionary(); @@ -319,5 +328,21 @@ public override bool TryGetPreviousLambda(SyntaxNode lambdaOrLambdaBodySyntax, b lambdaId = default; return false; } + + public override int? GetFirstUnusedStateMachineState(bool increasing) + => increasing ? _firstUnusedIncreasingStateMachineState : _firstUnusedDecreasingStateMachineState; + + public override bool TryGetPreviousStateMachineState(SyntaxNode syntax, out int stateOrdinal) + { + if (_stateMachineStateMap != null && + TryGetPreviousSyntaxOffset(syntax, out int syntaxOffset) && + _stateMachineStateMap.TryGetValue(syntaxOffset, out stateOrdinal)) + { + return true; + } + + stateOrdinal = -1; + return false; + } } } diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinueMethodDebugInformation.cs b/src/Compilers/Core/Portable/Emit/EditAndContinueMethodDebugInformation.cs index c15f3a874c9b2..4cc95b0b8b427 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinueMethodDebugInformation.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinueMethodDebugInformation.cs @@ -22,8 +22,14 @@ public readonly struct EditAndContinueMethodDebugInformation internal readonly ImmutableArray LocalSlots; internal readonly ImmutableArray Lambdas; internal readonly ImmutableArray Closures; - - internal EditAndContinueMethodDebugInformation(int methodOrdinal, ImmutableArray localSlots, ImmutableArray closures, ImmutableArray lambdas) + internal readonly ImmutableArray StateMachineStates; + + internal EditAndContinueMethodDebugInformation( + int methodOrdinal, + ImmutableArray localSlots, + ImmutableArray closures, + ImmutableArray lambdas, + ImmutableArray stateMachineStates) { Debug.Assert(methodOrdinal >= -1); @@ -31,6 +37,7 @@ internal EditAndContinueMethodDebugInformation(int methodOrdinal, ImmutableArray LocalSlots = localSlots; Lambdas = lambdas; Closures = closures; + StateMachineStates = stateMachineStates; } /// @@ -40,9 +47,25 @@ internal EditAndContinueMethodDebugInformation(int methodOrdinal, ImmutableArray /// Lambda and closure map. /// Invalid data. public static EditAndContinueMethodDebugInformation Create(ImmutableArray compressedSlotMap, ImmutableArray compressedLambdaMap) + => Create(compressedSlotMap, compressedLambdaMap, compressedStateMachineStateMap: default); + + + /// + /// Deserializes Edit and Continue method debug information from specified blobs. + /// + /// Local variable slot map. + /// Lambda and closure map. + /// State machine suspension points, if the method is the MoveNext method of the state machine. + /// Invalid data. + public static EditAndContinueMethodDebugInformation Create(ImmutableArray compressedSlotMap, ImmutableArray compressedLambdaMap, ImmutableArray compressedStateMachineStateMap) { UncompressLambdaMap(compressedLambdaMap, out var methodOrdinal, out var closures, out var lambdas); - return new EditAndContinueMethodDebugInformation(methodOrdinal, UncompressSlotMap(compressedSlotMap), closures, lambdas); + return new EditAndContinueMethodDebugInformation( + methodOrdinal, + UncompressSlotMap(compressedSlotMap), + closures, + lambdas, + UncompressStateMachineStates(compressedStateMachineStateMap)); } private static InvalidDataException CreateInvalidDataException(ImmutableArray data, int offset) @@ -277,5 +300,56 @@ internal void SerializeLambdaMap(BlobBuilder writer) } #endregion + + #region State Machine States + + /// Invalid data. + private static unsafe ImmutableArray UncompressStateMachineStates(ImmutableArray compressedStateMachineStates) + { + if (compressedStateMachineStates.IsDefaultOrEmpty) + { + return default; + } + + var mapBuilder = ArrayBuilder.GetInstance(); + + fixed (byte* ptr = &compressedStateMachineStates.ToArray()[0]) + { + var blobReader = new BlobReader(ptr, compressedStateMachineStates.Length); + + try + { + int count = blobReader.ReadCompressedInteger(); + + while (count > 0) + { + int stateNumber = blobReader.ReadCompressedSignedInteger(); + int syntaxOffset = blobReader.ReadCompressedInteger(); + + mapBuilder.Add(new StateMachineStateDebugInfo(syntaxOffset, stateNumber)); + count--; + } + } + catch (BadImageFormatException) + { + throw CreateInvalidDataException(compressedStateMachineStates, blobReader.Offset); + } + } + + return mapBuilder.ToImmutableAndFree(); + } + + internal void SerializeStateMachineStates(BlobBuilder writer) + { + writer.WriteCompressedInteger(StateMachineStates.Length); + + foreach (StateMachineStateDebugInfo state in StateMachineStates) + { + writer.WriteCompressedSignedInteger(state.StateNumber); + writer.WriteCompressedInteger(state.SyntaxOffset); + } + } + + #endregion } } diff --git a/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedMethod.cs b/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedMethod.cs index 66692ffdf4ed3..6d8771f789e6f 100644 --- a/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedMethod.cs +++ b/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedMethod.cs @@ -161,6 +161,9 @@ public EmptyBody(CommonEmbeddedMethod method) ImmutableArray Cci.IMethodBody.LambdaDebugInfo => default(ImmutableArray); + public StateMachineStatesDebugInfo StateMachineStatesDebugInfo + => default; + public DebugId MethodId => default(DebugId); } diff --git a/src/Compilers/Core/Portable/MetadataReader/PEModule.cs b/src/Compilers/Core/Portable/MetadataReader/PEModule.cs index a4704092eb521..ffb6052dd673c 100644 --- a/src/Compilers/Core/Portable/MetadataReader/PEModule.cs +++ b/src/Compilers/Core/Portable/MetadataReader/PEModule.cs @@ -1722,6 +1722,11 @@ private bool TryExtractValueFromAttribute(CustomAttributeHandle handle, out T } #nullable disable + internal bool HasStateMachineAttribute(MethodDefinitionHandle handle, out string stateMachineTypeName) + => HasStringValuedAttribute(handle, AttributeDescription.AsyncStateMachineAttribute, out stateMachineTypeName) || + HasStringValuedAttribute(handle, AttributeDescription.IteratorStateMachineAttribute, out stateMachineTypeName) || + HasStringValuedAttribute(handle, AttributeDescription.AsyncIteratorStateMachineAttribute, out stateMachineTypeName); + internal bool HasStringValuedAttribute(EntityHandle token, AttributeDescription description, out string value) { AttributeInfo info = FindTargetAttribute(token, description); diff --git a/src/Compilers/Core/Portable/PEWriter/CustomDebugInfoWriter.cs b/src/Compilers/Core/Portable/PEWriter/CustomDebugInfoWriter.cs index 2371acc5d48a8..72fc9d41e1336 100644 --- a/src/Compilers/Core/Portable/PEWriter/CustomDebugInfoWriter.cs +++ b/src/Compilers/Core/Portable/PEWriter/CustomDebugInfoWriter.cs @@ -147,6 +147,14 @@ internal static void SerializeCustomDebugInformation(ref CustomDebugInfoEncoder debugInfo, (info, builder) => info.SerializeLambdaMap(builder)); } + + if (!debugInfo.StateMachineStates.IsDefaultOrEmpty) + { + encoder.AddRecord( + CustomDebugInfoKind.EditAndContinueStateMachineStateMap, + debugInfo, + (info, builder) => info.SerializeStateMachineStates(builder)); + } } private static ArrayBuilder GetLocalInfoToSerialize( diff --git a/src/Compilers/Core/Portable/PEWriter/Members.cs b/src/Compilers/Core/Portable/PEWriter/Members.cs index fcb78a61af057..0625117b7b837 100644 --- a/src/Compilers/Core/Portable/PEWriter/Members.cs +++ b/src/Compilers/Core/Portable/PEWriter/Members.cs @@ -475,6 +475,7 @@ ImmutableArray ExceptionRegions ImmutableArray ClosureDebugInfo { get; } ImmutableArray LambdaDebugInfo { get; } + StateMachineStatesDebugInfo StateMachineStatesDebugInfo { get; } DynamicAnalysisMethodBodyData DynamicAnalysisData { get; } } diff --git a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.PortablePdb.cs b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.PortablePdb.cs index bfd660f5e4b1f..74b080264b787 100644 --- a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.PortablePdb.cs +++ b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.PortablePdb.cs @@ -817,6 +817,18 @@ private void SerializeEncMethodDebugInformation(IMethodBody methodBody, MethodDe kind: _debugMetadataOpt.GetOrAddGuid(PortableCustomDebugInfoKinds.EncLambdaAndClosureMap), value: _debugMetadataOpt.GetOrAddBlob(writer)); } + + if (!encInfo.StateMachineStates.IsDefaultOrEmpty) + { + var writer = new BlobBuilder(); + + encInfo.SerializeStateMachineStates(writer); + + _debugMetadataOpt.AddCustomDebugInformation( + parent: method, + kind: _debugMetadataOpt.GetOrAddGuid(PortableCustomDebugInfoKinds.EncStateMachineStateMap), + value: _debugMetadataOpt.GetOrAddBlob(writer)); + } } #endregion diff --git a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs index 17defcf93881b..e8fd04f5faace 100644 --- a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs +++ b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs @@ -4054,7 +4054,12 @@ internal static EditAndContinueMethodDebugInformation GetEncMethodDebugInfo(IMet encLocalSlots = GetLocalSlotDebugInfos(encSlotInfo); } - return new EditAndContinueMethodDebugInformation(methodBody.MethodId.Ordinal, encLocalSlots, methodBody.ClosureDebugInfo, methodBody.LambdaDebugInfo); + return new EditAndContinueMethodDebugInformation( + methodBody.MethodId.Ordinal, + encLocalSlots, + methodBody.ClosureDebugInfo, + methodBody.LambdaDebugInfo, + methodBody.StateMachineStatesDebugInfo.States); } internal static ImmutableArray GetLocalSlotDebugInfos(ImmutableArray locals) diff --git a/src/Compilers/Core/Portable/PEWriter/RootModuleStaticConstructor.cs b/src/Compilers/Core/Portable/PEWriter/RootModuleStaticConstructor.cs index b397eb48370b9..b6001e1a37a07 100644 --- a/src/Compilers/Core/Portable/PEWriter/RootModuleStaticConstructor.cs +++ b/src/Compilers/Core/Portable/PEWriter/RootModuleStaticConstructor.cs @@ -161,8 +161,11 @@ public RootModuleStaticConstructor(ITypeDefinition containingTypeDefinition, Imm public ImmutableArray LambdaDebugInfo => ImmutableArray.Empty; + public StateMachineStatesDebugInfo StateMachineStatesDebugInfo => default; + public DynamicAnalysisMethodBodyData DynamicAnalysisData => null; + public sealed override bool Equals(object obj) { // It is not supported to rely on default equality of these Cci objects, an explicit way to compare and hash them should be used. diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index c2331cd21ec09..16044f66b7b9f 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -54,6 +54,7 @@ Microsoft.CodeAnalysis.SymbolVisitor Microsoft.CodeAnalysis.SymbolVisitor.SymbolVisitor() -> void override sealed Microsoft.CodeAnalysis.Diagnostic.Equals(object? obj) -> bool *REMOVED*static Microsoft.CodeAnalysis.SyntaxNodeExtensions.ReplaceSyntax(this TRoot! root, System.Collections.Generic.IEnumerable! nodes, System.Func! computeReplacementNode, System.Collections.Generic.IEnumerable! tokens, System.Func! computeReplacementToken, System.Collections.Generic.IEnumerable! trivia, System.Func! computeReplacementTrivia) -> TRoot! +static Microsoft.CodeAnalysis.Emit.EditAndContinueMethodDebugInformation.Create(System.Collections.Immutable.ImmutableArray compressedSlotMap, System.Collections.Immutable.ImmutableArray compressedLambdaMap, System.Collections.Immutable.ImmutableArray compressedStateMachineStateMap) -> Microsoft.CodeAnalysis.Emit.EditAndContinueMethodDebugInformation static Microsoft.CodeAnalysis.SyntaxNodeExtensions.ReplaceSyntax(this TRoot! root, System.Collections.Generic.IEnumerable? nodes, System.Func? computeReplacementNode, System.Collections.Generic.IEnumerable? tokens, System.Func? computeReplacementToken, System.Collections.Generic.IEnumerable? trivia, System.Func? computeReplacementTrivia) -> TRoot! const Microsoft.CodeAnalysis.WellKnownMemberNames.CheckedDecrementOperatorName = "op_CheckedDecrement" -> string! const Microsoft.CodeAnalysis.WellKnownMemberNames.CheckedIncrementOperatorName = "op_CheckedIncrement" -> string! @@ -90,5 +91,4 @@ virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitPointerTyp virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitProperty(Microsoft.CodeAnalysis.IPropertySymbol! symbol, TArgument argument) -> TResult virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitRangeVariable(Microsoft.CodeAnalysis.IRangeVariableSymbol! symbol, TArgument argument) -> TResult virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitTypeParameter(Microsoft.CodeAnalysis.ITypeParameterSymbol! symbol, TArgument argument) -> TResult - Microsoft.CodeAnalysis.Operations.BinaryOperatorKind.UnsignedRightShift = 25 -> Microsoft.CodeAnalysis.Operations.BinaryOperatorKind \ No newline at end of file diff --git a/src/Compilers/Core/Portable/WellKnownMember.cs b/src/Compilers/Core/Portable/WellKnownMember.cs index a9e2796429218..350ba18c96400 100644 --- a/src/Compilers/Core/Portable/WellKnownMember.cs +++ b/src/Compilers/Core/Portable/WellKnownMember.cs @@ -499,6 +499,7 @@ internal enum WellKnownMember System_Runtime_CompilerServices_ITuple__get_Length, System_InvalidOperationException__ctor, + System_InvalidOperationException__ctorString, System_Runtime_CompilerServices_SwitchExpressionException__ctor, System_Runtime_CompilerServices_SwitchExpressionException__ctorObject, diff --git a/src/Compilers/Core/Portable/WellKnownMembers.cs b/src/Compilers/Core/Portable/WellKnownMembers.cs index 390cb2ab3281e..b4c7bb4389ac9 100644 --- a/src/Compilers/Core/Portable/WellKnownMembers.cs +++ b/src/Compilers/Core/Portable/WellKnownMembers.cs @@ -3444,6 +3444,14 @@ static WellKnownMembers() 0, // Method Signature (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, + // System_InvalidOperationException__ctorString + (byte)MemberFlags.Constructor, // Flags + (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_InvalidOperationException - WellKnownType.ExtSentinel), // DeclaringTypeId + 0, // Arity + 1, // Method Signature + (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, + (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_String, + // System_Runtime_CompilerServices_SwitchExpressionException__ctor (byte)MemberFlags.Constructor, // Flags (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Runtime_CompilerServices_SwitchExpressionException - WellKnownType.ExtSentinel),// DeclaringTypeId @@ -4024,6 +4032,7 @@ static WellKnownMembers() "get_Item", // System_Runtime_CompilerServices_ITuple__get_Item "get_Length", // System_Runtime_CompilerServices_ITuple__get_Length ".ctor", // System_InvalidOperationException__ctor + ".ctor", // System_InvalidOperationException__ctorString ".ctor", // System_Runtime_CompilerServices_SwitchExpressionException__ctor ".ctor", // System_Runtime_CompilerServices_SwitchExpressionException__ctorObject "Equals", // System_Threading_CancellationToken__Equals diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.cs.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.cs.xlf index 4aa76eeed541c..2fa852c159d6c 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.cs.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.cs.xlf @@ -39,6 +39,16 @@ Pokud chcete tento analyzátor zakázat, potlačte následující diagnostiku: {0} {0}: Comma-separated list of diagnostic IDs + + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + + + + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + + The hintName '{0}' contains an invalid character '{1}' at position {2}. {0} hintName obsahuje neplatný znak {1} na pozici {2}. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.de.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.de.xlf index 00ea4369d37cd..364047feec649 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.de.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.de.xlf @@ -39,6 +39,16 @@ Unterdrücken Sie die folgende Diagnose, um dieses Analysetool zu deaktivieren: {0} {0}: Comma-separated list of diagnostic IDs + + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + + + + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + + The hintName '{0}' contains an invalid character '{1}' at position {2}. Der hintName "{0}" enthält ein ungültiges Zeichen "{1}" an Position {2}. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.es.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.es.xlf index f7b6c0d69253b..1253ec5496d77 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.es.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.es.xlf @@ -39,6 +39,16 @@ Suprima el diagnóstico siguiente para deshabilitar este analizador: {0} {0}: Comma-separated list of diagnostic IDs + + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + + + + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + + The hintName '{0}' contains an invalid character '{1}' at position {2}. El elemento hintName "{0}" contiene un carácter no válido "{1}" en la posición {2}. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.fr.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.fr.xlf index 5240ce918f8c4..967be7424cccc 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.fr.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.fr.xlf @@ -39,6 +39,16 @@ Supprimez les diagnostics suivants pour désactiver cet analyseur : {0} {0}: Comma-separated list of diagnostic IDs + + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + + + + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + + The hintName '{0}' contains an invalid character '{1}' at position {2}. Le hintName « {0} » contient un caractère non valide « {1} » à la position {2}. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.it.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.it.xlf index bc850fd6a3102..e968e21f33ce0 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.it.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.it.xlf @@ -39,6 +39,16 @@ Per disabilitare questo analizzatore, eliminare la diagnostica seguente: {0} {0}: Comma-separated list of diagnostic IDs + + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + + + + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + + The hintName '{0}' contains an invalid character '{1}' at position {2}. L'elemento hintName '{0}' contiene un carattere non valido '{1}' alla posizione {2}. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ja.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ja.xlf index 75847de1ed2f6..ada7f1dafc681 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ja.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ja.xlf @@ -39,6 +39,16 @@ 次の診断を抑制して、このアナライザーを無効にします: {0} {0}: Comma-separated list of diagnostic IDs + + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + + + + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + + The hintName '{0}' contains an invalid character '{1}' at position {2}. hintName {0} の位置 {2} に無効な文字 '{1}' が含まれています。 diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ko.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ko.xlf index 097be4f235c04..03be4626a83c9 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ko.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ko.xlf @@ -39,6 +39,16 @@ 이 분석기를 사용하지 않도록 설정하려면 다음 진단이 표시되지 않도록 설정하세요. {0} {0}: Comma-separated list of diagnostic IDs + + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + + + + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + + The hintName '{0}' contains an invalid character '{1}' at position {2}. hintName의 {0} 위치 {2}에 잘못된 문자 '{1}'이(가) 있습니다. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pl.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pl.xlf index aed49848d2d89..bb38bea3940f1 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pl.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pl.xlf @@ -39,6 +39,16 @@ Pomiń następującą diagnostykę, aby wyłączyć ten analizator: {0} {0}: Comma-separated list of diagnostic IDs + + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + + + + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + + The hintName '{0}' contains an invalid character '{1}' at position {2}. Element hintName „{0}” zawiera nieprawidłowy znak „{1}” na pozycji {2}. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pt-BR.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pt-BR.xlf index aa6850941c6ee..1c522fba6c113 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pt-BR.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.pt-BR.xlf @@ -39,6 +39,16 @@ Suprimir os seguintes diagnósticos para desabilitar este analisador: {0} {0}: Comma-separated list of diagnostic IDs + + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + + + + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + + The hintName '{0}' contains an invalid character '{1}' at position {2}. O hintName '{0}' contém um caractere inválido '{1}' na posição {2}. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ru.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ru.xlf index 625cd0fd53384..480ee2cc98470 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ru.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.ru.xlf @@ -39,6 +39,16 @@ Отключите следующую диагностику, чтобы отключить этот анализатор: {0} {0}: Comma-separated list of diagnostic IDs + + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + + + + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + + The hintName '{0}' contains an invalid character '{1}' at position {2}. hintName "{0}" содержит недопустимый символ "{1}" в позиции {2}. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.tr.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.tr.xlf index 0fb46e1e726b6..5186af765f636 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.tr.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.tr.xlf @@ -39,6 +39,16 @@ Bu çözümleyiciyi devre dışı bırakmak için şu tanılamaları gizleyin: {0} {0}: Comma-separated list of diagnostic IDs + + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + + + + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + + The hintName '{0}' contains an invalid character '{1}' at position {2}. hintName '{0}', {2} konumunda geçersiz bir '{1}' karakteri içeriyor. diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hans.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hans.xlf index b22f62b9662fc..9714b0083f904 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hans.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hans.xlf @@ -39,6 +39,16 @@ 取消以下诊断以禁用此分析器: {0} {0}: Comma-separated list of diagnostic IDs + + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + + + + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + + The hintName '{0}' contains an invalid character '{1}' at position {2}. hintName“{0}”在位置 {2} 处包含无效字符“{1}”。 diff --git a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hant.xlf b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hant.xlf index fec16f40c1ab8..d7100f2db3ca8 100644 --- a/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hant.xlf +++ b/src/Compilers/Core/Portable/xlf/CodeAnalysisResources.zh-Hant.xlf @@ -39,6 +39,16 @@ 請隱藏下列診斷以停用此分析器: {0} {0}: Comma-separated list of diagnostic IDs + + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + Edit and Continue can't resume suspended asynchronous method since the corresponding await expression has been deleted + + + + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + Edit and Continue can't resume suspended iterator since the corresponding yield return statement has been deleted + + The hintName '{0}' contains an invalid character '{1}' at position {2}. 位置 {2} 的 hintName {0} 包含無效的字元 '{1}'。 diff --git a/src/Compilers/Test/Core/Compilation/CompilationTestDataExtensions.cs b/src/Compilers/Test/Core/Compilation/CompilationTestDataExtensions.cs index 11e63278c95ab..0a7d4b5916ba8 100644 --- a/src/Compilers/Test/Core/Compilation/CompilationTestDataExtensions.cs +++ b/src/Compilers/Test/Core/Compilation/CompilationTestDataExtensions.cs @@ -108,7 +108,8 @@ internal static EditAndContinueMethodDebugInformation GetEncDebugInfo(this Compi 0, Cci.MetadataWriter.GetLocalSlotDebugInfos(methodData.ILBuilder.LocalSlotManager.LocalsInOrder()), closures: ImmutableArray.Empty, - lambdas: ImmutableArray.Empty); + lambdas: ImmutableArray.Empty, + stateMachineStates: ImmutableArray.Empty); } internal static Func EncDebugInfoProvider(this CompilationTestData.MethodData methodData) diff --git a/src/Compilers/Test/Core/MarkedSource/SourceWithMarkedNodes.cs b/src/Compilers/Test/Core/MarkedSource/SourceWithMarkedNodes.cs index 9b30cb6c8da06..24bab1d23ddc3 100644 --- a/src/Compilers/Test/Core/MarkedSource/SourceWithMarkedNodes.cs +++ b/src/Compilers/Test/Core/MarkedSource/SourceWithMarkedNodes.cs @@ -81,7 +81,7 @@ internal static string ClearTags(string source) } private static readonly Regex s_tags = new Regex( - @"[<][/]?[NMCL][:]?[:\.A-Za-z0-9]*[>]", + @"[<][/]?[NMCL][:][:\.A-Za-z0-9]*[>]", RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline); private static readonly Regex s_markerPattern = new Regex( @@ -93,7 +93,7 @@ internal static string ClearTags(string source) (?[0-9]+) # The first number after the colon is the Id ([.](?[0-9]+))? # Digits after a decimal point are the parent Id ([:](?[A-Za-z]+))? # A second colon separates the syntax kind - )? # Close the group for the things after the tag name + ) # Close the group for the things after the tag name [>] # Close tag ( # Start a group so that the closing tag is optional diff --git a/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb b/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb index 8a926154dfff4..b3ade194c24dd 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb @@ -315,6 +315,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic block:=body, lambdaDebugInfo:=ImmutableArray(Of LambdaDebugInfo).Empty, closureDebugInfo:=ImmutableArray(Of ClosureDebugInfo).Empty, + stateMachineStateDebugInfos:=ImmutableArray(Of StateMachineStateDebugInfo).Empty, stateMachineTypeOpt:=Nothing, variableSlotAllocatorOpt:=Nothing, debugDocumentProvider:=Nothing, @@ -886,6 +887,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic block:=boundBody, lambdaDebugInfo:=ImmutableArray(Of LambdaDebugInfo).Empty, closureDebugInfo:=ImmutableArray(Of ClosureDebugInfo).Empty, + stateMachineStateDebugInfos:=ImmutableArray(Of StateMachineStateDebugInfo).Empty, stateMachineTypeOpt:=Nothing, variableSlotAllocatorOpt:=Nothing, debugDocumentProvider:=If(_emitTestCoverageData, _debugDocumentProvider, Nothing), @@ -916,7 +918,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Private Sub CompileSynthesizedMethods(additionalTypes As ImmutableArray(Of NamedTypeSymbol)) Debug.Assert(_moduleBeingBuiltOpt IsNot Nothing) + Dim lambdaDebugInfoBuilder = ArrayBuilder(Of LambdaDebugInfo).GetInstance() + Dim closureDebugInfoBuilder = ArrayBuilder(Of ClosureDebugInfo).GetInstance() + Dim stateMachineStateDebugInfoBuilder = ArrayBuilder(Of StateMachineStateDebugInfo).GetInstance() Dim compilationState As New TypeCompilationState(_compilation, _moduleBeingBuiltOpt, initializeComponentOpt:=Nothing) + For Each additionalType In additionalTypes Dim methodOrdinal As Integer = 0 @@ -931,8 +937,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Dim lazyVariableSlotAllocator As VariableSlotAllocator = Nothing Dim statemachineTypeOpt As StateMachineTypeSymbol = Nothing - Dim lambdaDebugInfoBuilder = ArrayBuilder(Of LambdaDebugInfo).GetInstance() - Dim closureDebugInfoBuilder = ArrayBuilder(Of ClosureDebugInfo).GetInstance() Dim delegateRelaxationIdDispenser = 0 Dim dynamicAnalysisSpans As ImmutableArray(Of SourceSpan) = ImmutableArray(Of SourceSpan).Empty @@ -949,6 +953,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic lazyVariableSlotAllocator:=lazyVariableSlotAllocator, lambdaDebugInfoBuilder:=lambdaDebugInfoBuilder, closureDebugInfoBuilder:=closureDebugInfoBuilder, + stateMachineStateDebugInfoBuilder:=stateMachineStateDebugInfoBuilder, delegateRelaxationIdDispenser:=delegateRelaxationIdDispenser, stateMachineTypeOpt:=statemachineTypeOpt, allowOmissionOfConditionalCalls:=_moduleBeingBuiltOpt.AllowOmissionOfConditionalCalls, @@ -963,6 +968,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic rewrittenBody, lambdaDebugInfoBuilder.ToImmutable(), closureDebugInfoBuilder.ToImmutable(), + stateMachineStateDebugInfoBuilder.ToImmutable(), statemachineTypeOpt, lazyVariableSlotAllocator, debugDocumentProvider:=Nothing, @@ -971,9 +977,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic emitTestCoverageData:=False, dynamicAnalysisSpans:=dynamicAnalysisSpans) End If - - lambdaDebugInfoBuilder.Free() - closureDebugInfoBuilder.Free() End If _diagnostics.AddRange(diagnosticsThisMethod) @@ -988,6 +991,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic _moduleBeingBuiltOpt.SetMethodBody(method, emittedBody) End If + lambdaDebugInfoBuilder.Clear() + closureDebugInfoBuilder.Clear() + stateMachineStateDebugInfoBuilder.Clear() + methodOrdinal += 1 Next Next @@ -997,6 +1004,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End If compilationState.Free() + lambdaDebugInfoBuilder.Free() + closureDebugInfoBuilder.Free() + stateMachineStateDebugInfoBuilder.Free() End Sub Private Sub CompileSynthesizedMethods(compilationState As TypeCompilationState) @@ -1017,6 +1027,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic block:=methodWithBody.Body, lambdaDebugInfo:=ImmutableArray(Of LambdaDebugInfo).Empty, closureDebugInfo:=ImmutableArray(Of ClosureDebugInfo).Empty, + stateMachineStateDebugInfos:=ImmutableArray(Of StateMachineStateDebugInfo).Empty, stateMachineTypeOpt:=Nothing, variableSlotAllocatorOpt:=Nothing, debugDocumentProvider:=_debugDocumentProvider, @@ -1351,6 +1362,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Dim lambdaDebugInfoBuilder = ArrayBuilder(Of LambdaDebugInfo).GetInstance() Dim closureDebugInfoBuilder = ArrayBuilder(Of ClosureDebugInfo).GetInstance() + Dim stateMachineStateDebugInfoBuilder = ArrayBuilder(Of StateMachineStateDebugInfo).GetInstance() setterBody = Rewriter.LowerBodyOrInitializer(setter, withEventPropertyIdDispenser, @@ -1364,17 +1376,20 @@ Namespace Microsoft.CodeAnalysis.VisualBasic lazyVariableSlotAllocator:=Nothing, lambdaDebugInfoBuilder:=lambdaDebugInfoBuilder, closureDebugInfoBuilder:=closureDebugInfoBuilder, + stateMachineStateDebugInfoBuilder:=stateMachineStateDebugInfoBuilder, delegateRelaxationIdDispenser:=delegateRelaxationIdDispenser, stateMachineTypeOpt:=Nothing, allowOmissionOfConditionalCalls:=True, isBodySynthesized:=True) - ' There shall be no lambdas in the synthesized accessor but delegate relaxation conversions: - Debug.Assert(Not lambdaDebugInfoBuilder.Any()) - Debug.Assert(Not closureDebugInfoBuilder.Any()) + ' There shall be no lambdas and no awaits/yields in the synthesized accessor but delegate relaxation conversions: + Debug.Assert(lambdaDebugInfoBuilder.IsEmpty()) + Debug.Assert(closureDebugInfoBuilder.IsEmpty()) + Debug.Assert(stateMachineStateDebugInfoBuilder.IsEmpty()) lambdaDebugInfoBuilder.Free() closureDebugInfoBuilder.Free() + stateMachineStateDebugInfoBuilder.Free() compilationState.AddMethodWrapper(setter, setter, setterBody) _moduleBeingBuiltOpt.AddSynthesizedDefinition(containingType, setter.GetCciAdapter()) @@ -1459,6 +1474,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Dim allowOmissionOfConditionalCalls = _moduleBeingBuiltOpt Is Nothing OrElse _moduleBeingBuiltOpt.AllowOmissionOfConditionalCalls Dim lambdaDebugInfoBuilder = ArrayBuilder(Of LambdaDebugInfo).GetInstance() Dim closureDebugInfoBuilder = ArrayBuilder(Of ClosureDebugInfo).GetInstance() + Dim stateMachineStateDebugInfoBuilder = ArrayBuilder(Of StateMachineStateDebugInfo).GetInstance() Dim dynamicAnalysisSpans As ImmutableArray(Of SourceSpan) = ImmutableArray(Of SourceSpan).Empty body = Rewriter.LowerBodyOrInitializer(method, @@ -1473,6 +1489,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic lazyVariableSlotAllocator, lambdaDebugInfoBuilder, closureDebugInfoBuilder, + stateMachineStateDebugInfoBuilder, delegateRelaxationIdDispenser, stateMachineTypeOpt, allowOmissionOfConditionalCalls, @@ -1513,6 +1530,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic body, lambdaDebugInfoBuilder.ToImmutable(), closureDebugInfoBuilder.ToImmutable(), + stateMachineStateDebugInfoBuilder.ToImmutable(), stateMachineTypeOpt, lazyVariableSlotAllocator, _debugDocumentProvider, @@ -1540,6 +1558,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic block As BoundStatement, lambdaDebugInfo As ImmutableArray(Of LambdaDebugInfo), closureDebugInfo As ImmutableArray(Of ClosureDebugInfo), + stateMachineStateDebugInfos As ImmutableArray(Of StateMachineStateDebugInfo), stateMachineTypeOpt As StateMachineTypeSymbol, variableSlotAllocatorOpt As VariableSlotAllocator, debugDocumentProvider As DebugDocumentProvider, @@ -1671,6 +1690,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic stateMachineHoistedLocalScopes:=stateMachineHoistedLocalScopes, stateMachineHoistedLocalSlots:=stateMachineHoistedLocalSlots, stateMachineAwaiterSlots:=stateMachineAwaiterSlots, + stateMachineStatesDebugInfo:=StateMachineStatesDebugInfo.Create(variableSlotAllocatorOpt, stateMachineStateDebugInfos), stateMachineMoveNextDebugInfoOpt:=moveNextBodyDebugInfoOpt, dynamicAnalysisDataOpt:=dynamicAnalysisDataOpt) Finally diff --git a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/VisualBasicDefinitionMap.vb b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/VisualBasicDefinitionMap.vb index 1e0f115eadb06..98b2a823c3454 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/VisualBasicDefinitionMap.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/VisualBasicDefinitionMap.vb @@ -124,11 +124,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit End If End Function - Protected Overrides Function TryGetStateMachineType(methodHandle As EntityHandle) As ITypeSymbolInternal + Protected Overrides Function TryGetStateMachineType(methodHandle As MethodDefinitionHandle) As ITypeSymbolInternal Dim typeName As String = Nothing - If _metadataDecoder.Module.HasStringValuedAttribute(methodHandle, AttributeDescription.AsyncStateMachineAttribute, typeName) OrElse - _metadataDecoder.Module.HasStringValuedAttribute(methodHandle, AttributeDescription.IteratorStateMachineAttribute, typeName) Then - + If _metadataDecoder.Module.HasStateMachineAttribute(methodHandle, typeName) Then Return _metadataDecoder.GetTypeSymbolForSerializedType(typeName) End If diff --git a/src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.AsyncMethodToClassRewriter.vb b/src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.AsyncMethodToClassRewriter.vb index d67f29bc420c9..8f15aa7075c26 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.AsyncMethodToClassRewriter.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.AsyncMethodToClassRewriter.vb @@ -66,11 +66,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic builder As FieldSymbol, hoistedVariables As IReadOnlySet(Of Symbol), nonReusableLocalProxies As Dictionary(Of Symbol, CapturedSymbolOrExpression), + stateMachineStateDebugInfoBuilder As ArrayBuilder(Of StateMachineStateDebugInfo), slotAllocatorOpt As VariableSlotAllocator, owner As AsyncRewriter, diagnostics As BindingDiagnosticBag) - MyBase.New(F, state, hoistedVariables, nonReusableLocalProxies, slotAllocatorOpt, diagnostics) + MyBase.New(F, state, hoistedVariables, nonReusableLocalProxies, stateMachineStateDebugInfoBuilder, slotAllocatorOpt, diagnostics) Me._method = method Me._builder = builder diff --git a/src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.vb b/src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.vb index 80eccb8a90524..d1032d750de75 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/AsyncRewriter/AsyncRewriter.vb @@ -28,12 +28,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Public Sub New(body As BoundStatement, method As MethodSymbol, stateMachineType As AsyncStateMachine, + stateMachineStateDebugInfoBuilder As ArrayBuilder(Of StateMachineStateDebugInfo), slotAllocatorOpt As VariableSlotAllocator, asyncKind As AsyncMethodKind, compilationState As TypeCompilationState, diagnostics As BindingDiagnosticBag) - MyBase.New(body, method, stateMachineType, slotAllocatorOpt, compilationState, diagnostics) + MyBase.New(body, method, stateMachineType, stateMachineStateDebugInfoBuilder, slotAllocatorOpt, compilationState, diagnostics) Me._binder = CreateMethodBinder(method) Me._lookupOptions = LookupOptions.AllMethodsOfAnyArity Or LookupOptions.IgnoreExtensionMethods Or LookupOptions.NoBaseClassLookup @@ -71,6 +72,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Friend Overloads Shared Function Rewrite(body As BoundBlock, method As MethodSymbol, methodOrdinal As Integer, + stateMachineStateDebugInfoBuilder As ArrayBuilder(Of StateMachineStateDebugInfo), slotAllocatorOpt As VariableSlotAllocator, compilationState As TypeCompilationState, diagnostics As BindingDiagnosticBag, @@ -92,7 +94,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic compilationState.ModuleBuilderOpt.CompilationState.SetStateMachineType(method, stateMachineType) - Dim rewriter As New AsyncRewriter(body, method, stateMachineType, slotAllocatorOpt, asyncMethodKind, compilationState, diagnostics) + Dim rewriter As New AsyncRewriter(body, method, stateMachineType, stateMachineStateDebugInfoBuilder, slotAllocatorOpt, asyncMethodKind, compilationState, diagnostics) ' check if we have all the types we need If rewriter.EnsureAllSymbolsAndSignature() Then @@ -257,6 +259,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic builder:=_builderField, hoistedVariables:=hoistedVariables, nonReusableLocalProxies:=nonReusableLocalProxies, + StateDebugInfoBuilder, slotAllocatorOpt:=SlotAllocatorOpt, owner:=Me, diagnostics:=Diagnostics) diff --git a/src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.IteratorMethodToClassRewriter.vb b/src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.IteratorMethodToClassRewriter.vb index ce00cd5b7bf72..2eae48b96e447 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.IteratorMethodToClassRewriter.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.IteratorMethodToClassRewriter.vb @@ -29,10 +29,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic current As FieldSymbol, hoistedVariables As IReadOnlySet(Of Symbol), localProxies As Dictionary(Of Symbol, FieldSymbol), + stateMachineStateDebugInfoBuilder As ArrayBuilder(Of StateMachineStateDebugInfo), slotAllocatorOpt As VariableSlotAllocator, diagnostics As BindingDiagnosticBag) - MyBase.New(F, state, hoistedVariables, localProxies, slotAllocatorOpt, diagnostics) + MyBase.New(F, state, hoistedVariables, localProxies, stateMachineStateDebugInfoBuilder, slotAllocatorOpt, diagnostics) _current = current End Sub diff --git a/src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.vb b/src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.vb index e5d4b2b0bc25f..125c80376913d 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/IteratorRewriter/IteratorRewriter.vb @@ -23,11 +23,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic method As MethodSymbol, isEnumerable As Boolean, stateMachineType As IteratorStateMachine, + stateMachineStateDebugInfoBuilder As ArrayBuilder(Of StateMachineStateDebugInfo), slotAllocatorOpt As VariableSlotAllocator, compilationState As TypeCompilationState, diagnostics As BindingDiagnosticBag) - MyBase.New(body, method, stateMachineType, slotAllocatorOpt, compilationState, diagnostics) + MyBase.New(body, method, stateMachineType, stateMachineStateDebugInfoBuilder, slotAllocatorOpt, compilationState, diagnostics) Me._isEnumerable = isEnumerable @@ -46,6 +47,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Friend Overloads Shared Function Rewrite(body As BoundBlock, method As MethodSymbol, methodOrdinal As Integer, + stateMachineStateDebugInfoBuilder As ArrayBuilder(Of StateMachineStateDebugInfo), slotAllocatorOpt As VariableSlotAllocator, compilationState As TypeCompilationState, diagnostics As BindingDiagnosticBag, @@ -72,7 +74,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic compilationState.ModuleBuilderOpt.CompilationState.SetStateMachineType(method, stateMachineType) - Dim rewriter As New IteratorRewriter(body, method, isEnumerable, stateMachineType, slotAllocatorOpt, compilationState, diagnostics) + Dim rewriter As New IteratorRewriter(body, method, isEnumerable, stateMachineType, stateMachineStateDebugInfoBuilder, slotAllocatorOpt, compilationState, diagnostics) ' check if we have all the types we need If rewriter.EnsureAllSymbolsAndSignature() Then @@ -347,6 +349,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic current:=_currentField, hoistedVariables:=hoistedVariables, localProxies:=nonReusableLocalProxies, + StateDebugInfoBuilder, slotAllocatorOpt:=SlotAllocatorOpt, diagnostics:=Diagnostics) diff --git a/src/Compilers/VisualBasic/Portable/Lowering/LambdaRewriter/LambdaRewriter.vb b/src/Compilers/VisualBasic/Portable/Lowering/LambdaRewriter/LambdaRewriter.vb index 7a60d299baec6..28fb21526a96d 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/LambdaRewriter/LambdaRewriter.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/LambdaRewriter/LambdaRewriter.vb @@ -901,8 +901,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ' produce a unique method ordinal for the corresponding state machine type, whose name includes the (unique) method name. Const methodOrdinal As Integer = -1 + Dim stateMachineStateDebugInfosBuilder = ArrayBuilder(Of StateMachineStateDebugInfo).GetInstance() Dim slotAllocatorOpt = CompilationState.ModuleBuilderOpt.TryCreateVariableSlotAllocator(method, method.TopLevelMethod, Diagnostics.DiagnosticBag) - Return Rewriter.RewriteIteratorAndAsync(loweredBody, method, methodOrdinal, CompilationState, Diagnostics, slotAllocatorOpt, stateMachineTypeOpt) + Dim result = Rewriter.RewriteIteratorAndAsync(loweredBody, method, methodOrdinal, CompilationState, Diagnostics, stateMachineStateDebugInfosBuilder, slotAllocatorOpt, stateMachineTypeOpt) + stateMachineStateDebugInfosBuilder.Free() + Return result End Function Public Overrides Function VisitTryCast(node As BoundTryCast) As BoundNode diff --git a/src/Compilers/VisualBasic/Portable/Lowering/Rewriter.vb b/src/Compilers/VisualBasic/Portable/Lowering/Rewriter.vb index 91c2bdff8f81a..9c2f8e72bbf6a 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/Rewriter.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/Rewriter.vb @@ -26,6 +26,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ByRef lazyVariableSlotAllocator As VariableSlotAllocator, lambdaDebugInfoBuilder As ArrayBuilder(Of LambdaDebugInfo), closureDebugInfoBuilder As ArrayBuilder(Of ClosureDebugInfo), + stateMachineStateDebugInfoBuilder As ArrayBuilder(Of StateMachineStateDebugInfo), ByRef delegateRelaxationIdDispenser As Integer, ByRef stateMachineTypeOpt As StateMachineTypeSymbol, allowOmissionOfConditionalCalls As Boolean, @@ -108,7 +109,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return bodyWithoutLambdas End If - Dim bodyWithoutIteratorAndAsync = RewriteIteratorAndAsync(bodyWithoutLambdas, method, methodOrdinal, compilationState, localDiagnostics, lazyVariableSlotAllocator, stateMachineTypeOpt) + Dim bodyWithoutIteratorAndAsync = RewriteIteratorAndAsync(bodyWithoutLambdas, method, methodOrdinal, compilationState, localDiagnostics, stateMachineStateDebugInfoBuilder, lazyVariableSlotAllocator, stateMachineTypeOpt) diagnostics.AddRangeAndFree(localDiagnostics) @@ -127,6 +128,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic methodOrdinal As Integer, compilationState As TypeCompilationState, diagnostics As BindingDiagnosticBag, + stateMachineStateDebugInfoBuilder As ArrayBuilder(Of StateMachineStateDebugInfo), slotAllocatorOpt As VariableSlotAllocator, ByRef stateMachineTypeOpt As StateMachineTypeSymbol) As BoundBlock @@ -136,6 +138,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Dim bodyWithoutIterators = IteratorRewriter.Rewrite(bodyWithoutLambdas, method, methodOrdinal, + stateMachineStateDebugInfoBuilder, slotAllocatorOpt, compilationState, diagnostics, @@ -149,6 +152,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Dim bodyWithoutAsync = AsyncRewriter.Rewrite(bodyWithoutIterators, method, methodOrdinal, + stateMachineStateDebugInfoBuilder, slotAllocatorOpt, compilationState, diagnostics, diff --git a/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.StateMachineMethodToClassRewriter.vb b/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.StateMachineMethodToClassRewriter.vb index 7003970ca9c60..786aa909d716a 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.StateMachineMethodToClassRewriter.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.StateMachineMethodToClassRewriter.vb @@ -65,10 +65,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' Private ReadOnly _hoistedVariables As IReadOnlySet(Of Symbol) = Nothing + Private ReadOnly _stateDebugInfoBuilder As ArrayBuilder(Of StateMachineStateDebugInfo) + Public Sub New(F As SyntheticBoundNodeFactory, stateField As FieldSymbol, hoistedVariables As IReadOnlySet(Of Symbol), initialProxies As Dictionary(Of Symbol, TProxy), + stateMachineStateDebugInfoBuilder As ArrayBuilder(Of StateMachineStateDebugInfo), slotAllocatorOpt As VariableSlotAllocator, diagnostics As BindingDiagnosticBag) @@ -84,6 +87,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Me.StateField = stateField Me.CachedState = F.SynthesizedLocal(F.SpecialType(SpecialType.System_Int32), SynthesizedLocalKind.StateMachineCachedState, F.Syntax) Me._hoistedVariables = hoistedVariables + Me._stateDebugInfoBuilder = stateMachineStateDebugInfoBuilder For Each p In initialProxies Me.Proxies.Add(p.Key, p.Value) diff --git a/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.vb b/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.vb index a36f12afb3185..008be8c2623d7 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/StateMachineRewriter/StateMachineRewriter.vb @@ -28,6 +28,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Protected ReadOnly StateMachineType As SynthesizedContainer Protected ReadOnly SlotAllocatorOpt As VariableSlotAllocator Protected ReadOnly SynthesizedLocalOrdinals As SynthesizedLocalOrdinalsDispenser + Protected ReadOnly StateDebugInfoBuilder As ArrayBuilder(Of StateMachineStateDebugInfo) Protected StateField As FieldSymbol Protected nonReusableLocalProxies As Dictionary(Of Symbol, TProxy) @@ -38,6 +39,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Protected Sub New(body As BoundStatement, method As MethodSymbol, stateMachineType As StateMachineTypeSymbol, + stateMachineStateDebugInfoBuilder As ArrayBuilder(Of StateMachineStateDebugInfo), slotAllocatorOpt As VariableSlotAllocator, compilationState As TypeCompilationState, diagnostics As BindingDiagnosticBag) @@ -55,6 +57,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Me.SlotAllocatorOpt = slotAllocatorOpt Me.Diagnostics = diagnostics Me.SynthesizedLocalOrdinals = New SynthesizedLocalOrdinalsDispenser() + Me.StateDebugInfoBuilder = stateMachineStateDebugInfoBuilder Me.nonReusableLocalProxies = New Dictionary(Of Symbol, TProxy)() Me.F = New SyntheticBoundNodeFactory(method, method, method.ContainingType, body.Syntax, compilationState, diagnostics) diff --git a/src/Dependencies/CodeAnalysis.Debugging/CustomDebugInfoKind.cs b/src/Dependencies/CodeAnalysis.Debugging/CustomDebugInfoKind.cs index afaf08923233f..9be8932163b09 100644 --- a/src/Dependencies/CodeAnalysis.Debugging/CustomDebugInfoKind.cs +++ b/src/Dependencies/CodeAnalysis.Debugging/CustomDebugInfoKind.cs @@ -62,5 +62,10 @@ internal enum CustomDebugInfoKind : byte /// C# and VB. Tuple element names for local variables and constants. /// TupleElementNames = 8, + + /// + /// C# and VB. Syntax offsets of nodes associated with state machine states in an async/iterator method and their corresponding state numbers. + /// + EditAndContinueStateMachineStateMap = 9, } } diff --git a/src/Dependencies/CodeAnalysis.Debugging/PortableCustomDebugInfoKinds.cs b/src/Dependencies/CodeAnalysis.Debugging/PortableCustomDebugInfoKinds.cs index d05cb8526a91b..4e0e325055ab0 100644 --- a/src/Dependencies/CodeAnalysis.Debugging/PortableCustomDebugInfoKinds.cs +++ b/src/Dependencies/CodeAnalysis.Debugging/PortableCustomDebugInfoKinds.cs @@ -17,6 +17,7 @@ internal static class PortableCustomDebugInfoKinds public static readonly Guid DefaultNamespace = new("58b2eab6-209f-4e4e-a22c-b2d0f910c782"); public static readonly Guid EncLocalSlotMap = new("755F52A8-91C5-45BE-B4B8-209571E552BD"); public static readonly Guid EncLambdaAndClosureMap = new("A643004C-0240-496F-A783-30D64F4979DE"); + public static readonly Guid EncStateMachineStateMap = new("8B78CD68-2EDE-420B-980B-E15884B8AAA3"); public static readonly Guid SourceLink = new("CC110556-A091-4D38-9FEC-25AB9A351A6A"); public static readonly Guid EmbeddedSource = new("0E8A571B-6926-466E-B4AD-8AB04611F5FE"); public static readonly Guid CompilationMetadataReferences = new("7E4D4708-096E-4C5C-AEDA-CB10BA6A740D"); diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationExtensions.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationExtensions.cs index 4401a643f5afd..932effdfbd4e9 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationExtensions.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationExtensions.cs @@ -38,20 +38,11 @@ internal static PEMethodSymbol GetSourceMethod(this CSharpCompilation compilatio { foreach (var member in containingType.ContainingType.GetMembers(sourceMethodName)) { - if (member is PEMethodSymbol candidateMethod) + if (member is PEMethodSymbol candidateMethod && + metadataDecoder.Module.HasStateMachineAttribute(candidateMethod.Handle, out var stateMachineTypeName) && + metadataDecoder.GetTypeSymbolForSerializedType(stateMachineTypeName).OriginalDefinition.Equals(containingType)) { - var module = metadataDecoder.Module; - methodHandle = candidateMethod.Handle; - string stateMachineTypeName; - if (module.HasStringValuedAttribute(methodHandle, AttributeDescription.AsyncStateMachineAttribute, out stateMachineTypeName) || - module.HasStringValuedAttribute(methodHandle, AttributeDescription.IteratorStateMachineAttribute, out stateMachineTypeName) || - module.HasStringValuedAttribute(methodHandle, AttributeDescription.AsyncIteratorStateMachineAttribute, out stateMachineTypeName)) - { - if (metadataDecoder.GetTypeSymbolForSerializedType(stateMachineTypeName).OriginalDefinition.Equals(containingType)) - { - return candidateMethod; - } - } + return candidateMethod; } } } diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EEAssemblyBuilder.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EEAssemblyBuilder.cs index 5b1cb9fe323c1..bb174945a96de 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EEAssemblyBuilder.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EEAssemblyBuilder.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.Symbols; using Roslyn.Utilities; using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Reflection.Metadata; @@ -173,6 +174,13 @@ public override bool TryGetPreviousLambda(SyntaxNode lambdaOrLambdaBodySyntax, b return false; } + public override bool TryGetPreviousStateMachineState(SyntaxNode awaitOrYieldSyntax, out int stateOrdinal) + { + stateOrdinal = 0; + return false; + } + + public override int? GetFirstUnusedStateMachineState(bool increasing) => null; public override string? PreviousStateMachineTypeName => null; public override int PreviousHoistedLocalSlotCount => 0; public override int PreviousAwaiterSlotCount => 0; diff --git a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/CompilationExtensions.vb b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/CompilationExtensions.vb index 90096eaf0d461..78ac4b0404922 100644 --- a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/CompilationExtensions.vb +++ b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/CompilationExtensions.vb @@ -35,16 +35,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator For Each member In containingType.ContainingType.GetMembers(sourceMethodName) Dim candidateMethod = TryCast(member, PEMethodSymbol) If candidateMethod IsNot Nothing Then - Dim [module] = metadataDecoder.Module - methodHandle = candidateMethod.Handle Dim stateMachineTypeName As String = Nothing - If [module].HasStringValuedAttribute(methodHandle, AttributeDescription.AsyncStateMachineAttribute, stateMachineTypeName) OrElse - [module].HasStringValuedAttribute(methodHandle, AttributeDescription.IteratorStateMachineAttribute, stateMachineTypeName) OrElse - [module].HasStringValuedAttribute(methodHandle, AttributeDescription.AsyncIteratorStateMachineAttribute, stateMachineTypeName) _ - Then - If metadataDecoder.GetTypeSymbolForSerializedType(stateMachineTypeName).OriginalDefinition.Equals(containingType) Then - Return candidateMethod - End If + If metadataDecoder.Module.HasStateMachineAttribute(candidateMethod.Handle, stateMachineTypeName) AndAlso + metadataDecoder.GetTypeSymbolForSerializedType(stateMachineTypeName).OriginalDefinition.Equals(containingType) Then + Return candidateMethod End If End If Next diff --git a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EEAssemblyBuilder.vb b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EEAssemblyBuilder.vb index 4e2cb1a42a5b5..aad85d9ce0e75 100644 --- a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EEAssemblyBuilder.vb +++ b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EEAssemblyBuilder.vb @@ -191,6 +191,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator Return False End Function + Public Overrides Function TryGetPreviousStateMachineState(awaitOrYieldSyntax As SyntaxNode, ByRef stateOrdinal As Integer) As Boolean + stateOrdinal = 0 + Return False + End Function + + Public Overrides Function GetFirstUnusedStateMachineState(increasing As Boolean) As Integer? + Return Nothing + End Function + Public Overrides ReadOnly Property PreviousStateMachineTypeName As String Get Return Nothing diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueMethodDebugInfoReader.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueMethodDebugInfoReader.cs index 98917b86fbc76..cbc870e77d4dc 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueMethodDebugInfoReader.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueMethodDebugInfoReader.cs @@ -81,18 +81,19 @@ public override EditAndContinueMethodDebugInformation GetDebugInfo(MethodDefinit try { - ImmutableArray localSlots, lambdaMap; + ImmutableArray localSlots, lambdaMap, stateMachineSuspensionPoints; if (debugInfo != null) { localSlots = CustomDebugInfoReader.TryGetCustomDebugInfoRecord(debugInfo, CustomDebugInfoKind.EditAndContinueLocalSlotMap); lambdaMap = CustomDebugInfoReader.TryGetCustomDebugInfoRecord(debugInfo, CustomDebugInfoKind.EditAndContinueLambdaMap); + stateMachineSuspensionPoints = CustomDebugInfoReader.TryGetCustomDebugInfoRecord(debugInfo, CustomDebugInfoKind.EditAndContinueStateMachineStateMap); } else { - localSlots = lambdaMap = default; + localSlots = lambdaMap = stateMachineSuspensionPoints = default; } - return EditAndContinueMethodDebugInformation.Create(localSlots, lambdaMap); + return EditAndContinueMethodDebugInformation.Create(localSlots, lambdaMap, stateMachineSuspensionPoints); } catch (InvalidOperationException e) when (FatalError.ReportAndCatch(e)) // likely a bug in the compiler/debugger { @@ -120,7 +121,8 @@ public override StandaloneSignatureHandle GetLocalSignature(MethodDefinitionHand public override EditAndContinueMethodDebugInformation GetDebugInfo(MethodDefinitionHandle methodHandle) => EditAndContinueMethodDebugInformation.Create( compressedSlotMap: GetCdiBytes(methodHandle, PortableCustomDebugInfoKinds.EncLocalSlotMap), - compressedLambdaMap: GetCdiBytes(methodHandle, PortableCustomDebugInfoKinds.EncLambdaAndClosureMap)); + compressedLambdaMap: GetCdiBytes(methodHandle, PortableCustomDebugInfoKinds.EncLambdaAndClosureMap), + compressedStateMachineStateMap: GetCdiBytes(methodHandle, PortableCustomDebugInfoKinds.EncStateMachineStateMap)); private ImmutableArray GetCdiBytes(MethodDefinitionHandle methodHandle, Guid kind) => TryGetCustomDebugInformation(_pdbReader, methodHandle, kind, out var cdi) ? diff --git a/src/Test/PdbUtilities/Reader/PdbTestUtilities.cs b/src/Test/PdbUtilities/Reader/PdbTestUtilities.cs index 0845b48e57a42..eeb34443188e0 100644 --- a/src/Test/PdbUtilities/Reader/PdbTestUtilities.cs +++ b/src/Test/PdbUtilities/Reader/PdbTestUtilities.cs @@ -47,7 +47,8 @@ ImmutableArray GetCdiBytes(Guid kind) => return EditAndContinueMethodDebugInformation.Create( compressedSlotMap: GetCdiBytes(PortableCustomDebugInfoKinds.EncLocalSlotMap), - compressedLambdaMap: GetCdiBytes(PortableCustomDebugInfoKinds.EncLambdaAndClosureMap)); + compressedLambdaMap: GetCdiBytes(PortableCustomDebugInfoKinds.EncLambdaAndClosureMap), + compressedStateMachineStateMap: GetCdiBytes(PortableCustomDebugInfoKinds.EncStateMachineStateMap)); } } diff --git a/src/Test/PdbUtilities/Reader/PdbValidation.cs b/src/Test/PdbUtilities/Reader/PdbValidation.cs index 37fc37f00f6e1..4d86ef5f9ec7c 100644 --- a/src/Test/PdbUtilities/Reader/PdbValidation.cs +++ b/src/Test/PdbUtilities/Reader/PdbValidation.cs @@ -642,7 +642,7 @@ internal static void VerifyPdbLambdasAndClosures(this Compilation compilation, S expectedTags.Sort((x, y) => x.StartIndex.CompareTo(y.StartIndex)); // Ensure the tag for the method start is the first element - expectedTags.Insert(0, new { Tag = "", StartIndex = methodStart }); + expectedTags.Insert(0, new { Tag = "", StartIndex = methodStart }); // Now reverse the list so we can insert without worrying about offsets expectedTags.Reverse();