using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp; internal sealed class AsyncExceptionHandlerRewriter : BoundTreeRewriterWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator { private sealed class AwaitInFinallyAnalysis : LabelCollector { private Dictionary> _labelsInInterestingTry; private HashSet _awaitContainingCatches; private bool _seenAwait; public AwaitInFinallyAnalysis(BoundStatement body) { _seenAwait = false; Visit(body); } public bool FinallyContainsAwaits(BoundTryStatement statement) { if (_labelsInInterestingTry != null) { return _labelsInInterestingTry.ContainsKey(statement); } return false; } internal bool CatchContainsAwait(BoundCatchBlock node) { if (_awaitContainingCatches != null) { return _awaitContainingCatches.Contains(node); } return false; } public bool ContainsAwaitInHandlers() { if (_labelsInInterestingTry == null) { return _awaitContainingCatches != null; } return true; } internal HashSet Labels(BoundTryStatement statement) { return _labelsInInterestingTry[statement]; } public override BoundNode VisitTryStatement(BoundTryStatement node) { HashSet hashSet = currentLabels; currentLabels = null; Visit(node.TryBlock); VisitList(node.CatchBlocks); bool seenAwait = _seenAwait; _seenAwait = false; Visit(node.FinallyBlockOpt); if (_seenAwait) { Dictionary> dictionary = _labelsInInterestingTry; if (dictionary == null) { dictionary = (_labelsInInterestingTry = new Dictionary>()); } dictionary.Add(node, currentLabels); currentLabels = hashSet; } else if (currentLabels == null) { currentLabels = hashSet; } else if (hashSet != null) { currentLabels.UnionWith(hashSet); } _seenAwait |= seenAwait; return null; } public override BoundNode VisitCatchBlock(BoundCatchBlock node) { bool seenAwait = _seenAwait; _seenAwait = false; BoundNode? result = base.VisitCatchBlock(node); if (_seenAwait) { HashSet awaitContainingCatches = _awaitContainingCatches; if (awaitContainingCatches == null) { awaitContainingCatches = (_awaitContainingCatches = new HashSet()); } _awaitContainingCatches.Add(node); } _seenAwait |= seenAwait; return result; } public override BoundNode VisitAwaitExpression(BoundAwaitExpression node) { _seenAwait = true; return base.VisitAwaitExpression(node); } public override BoundNode VisitLambda(BoundLambda node) { HashSet hashSet = currentLabels; bool seenAwait = _seenAwait; currentLabels = null; _seenAwait = false; base.VisitLambda(node); currentLabels = hashSet; _seenAwait = seenAwait; return null; } public override BoundNode VisitLocalFunctionStatement(BoundLocalFunctionStatement node) { HashSet hashSet = currentLabels; bool seenAwait = _seenAwait; currentLabels = null; _seenAwait = false; base.VisitLocalFunctionStatement(node); currentLabels = hashSet; _seenAwait = seenAwait; return null; } } private sealed class AwaitFinallyFrame { public readonly AwaitFinallyFrame ParentOpt; public readonly HashSet LabelsOpt; private readonly SyntaxNode _syntaxOpt; public Dictionary proxyLabels; public List proxiedLabels; public GeneratedLabelSymbol returnProxyLabel; public SynthesizedLocal returnValue; public AwaitFinallyFrame() { } public AwaitFinallyFrame(AwaitFinallyFrame parent, HashSet labelsOpt, SyntaxNode syntax) { ParentOpt = parent; LabelsOpt = labelsOpt; _syntaxOpt = syntax; } public bool IsRoot() { return ParentOpt == null; } public LabelSymbol ProxyLabelIfNeeded(LabelSymbol label) { if (IsRoot() || (LabelsOpt != null && LabelsOpt.Contains(label))) { return label; } Dictionary dictionary = proxyLabels; List list = proxiedLabels; if (dictionary == null) { dictionary = (proxyLabels = new Dictionary()); list = (proxiedLabels = new List()); } if (!dictionary.TryGetValue(label, out var value)) { value = new GeneratedLabelSymbol("proxy" + label.Name); dictionary.Add(label, value); list.Add(label); } return value; } public LabelSymbol ProxyReturnIfNeeded(MethodSymbol containingMethod, BoundExpression valueOpt, out SynthesizedLocal returnValue) { returnValue = null; if (IsRoot()) { return null; } GeneratedLabelSymbol generatedLabelSymbol = returnProxyLabel; if (generatedLabelSymbol == null) { generatedLabelSymbol = (returnProxyLabel = new GeneratedLabelSymbol("returnProxy")); } if (valueOpt != null) { returnValue = this.returnValue; if (returnValue == null) { this.returnValue = (returnValue = new SynthesizedLocal(containingMethod, TypeWithAnnotations.Create(valueOpt.Type), (SynthesizedLocalKind)20, _syntaxOpt, isPinned: false, isKnownToReferToTempIfReferenceType: false, (RefKind)0)); } } return generatedLabelSymbol; } } private sealed class AwaitCatchFrame { public readonly SynthesizedLocal pendingCaughtException; public readonly SynthesizedLocal pendingCatch; public readonly List handlers; private readonly AwaitCatchFrame _parentOpt; private readonly Dictionary _hoistedLocals; private readonly List _orderedHoistedLocals; public AwaitCatchFrame(SyntheticBoundNodeFactory F, TryStatementSyntax tryStatementSyntax, AwaitCatchFrame parentOpt) { pendingCaughtException = new SynthesizedLocal(F.CurrentFunction, TypeWithAnnotations.Create(F.SpecialType((SpecialType)1)), (SynthesizedLocalKind)25, (SyntaxNode)(object)tryStatementSyntax, isPinned: false, isKnownToReferToTempIfReferenceType: false, (RefKind)0); pendingCatch = new SynthesizedLocal(F.CurrentFunction, TypeWithAnnotations.Create(F.SpecialType((SpecialType)13)), (SynthesizedLocalKind)24, (SyntaxNode)(object)tryStatementSyntax, isPinned: false, isKnownToReferToTempIfReferenceType: false, (RefKind)0); handlers = new List(); _parentOpt = parentOpt; _hoistedLocals = new Dictionary(); _orderedHoistedLocals = new List(); } public void HoistLocal(LocalSymbol local, SyntheticBoundNodeFactory F) { if (!_hoistedLocals.Keys.Any((LocalSymbol l) => l.Name == local.Name && TypeSymbol.Equals(l.Type, local.Type, (TypeCompareKind)0))) { _hoistedLocals.Add(local, local); _orderedHoistedLocals.Add(local); } else { LocalSymbol localSymbol = F.SynthesizedLocal(local.Type, pendingCatch.SyntaxOpt, isPinned: false, isKnownToReferToTempIfReferenceType: false, (RefKind)0, (SynthesizedLocalKind)26); _hoistedLocals.Add(local, localSymbol); _orderedHoistedLocals.Add(localSymbol); } } public IEnumerable GetHoistedLocals() { return _orderedHoistedLocals; } public bool TryGetHoistedLocal(LocalSymbol originalLocal, out LocalSymbol hoistedLocal) { if (!_hoistedLocals.TryGetValue(originalLocal, out hoistedLocal)) { return _parentOpt?.TryGetHoistedLocal(originalLocal, out hoistedLocal) ?? false; } return true; } } private readonly SyntheticBoundNodeFactory _F; private readonly AwaitInFinallyAnalysis _analysis; private AwaitCatchFrame _currentAwaitCatchFrame; private AwaitFinallyFrame _currentAwaitFinallyFrame = new AwaitFinallyFrame(); private AsyncExceptionHandlerRewriter(MethodSymbol containingMethod, NamedTypeSymbol containingType, SyntheticBoundNodeFactory factory, AwaitInFinallyAnalysis analysis) { _F = factory; _F.CurrentFunction = containingMethod; _analysis = analysis; } public static BoundStatement Rewrite(MethodSymbol containingSymbol, NamedTypeSymbol containingType, BoundStatement statement, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics) { AwaitInFinallyAnalysis awaitInFinallyAnalysis = new AwaitInFinallyAnalysis(statement); if (!awaitInFinallyAnalysis.ContainsAwaitInHandlers()) { return statement; } SyntheticBoundNodeFactory factory = new SyntheticBoundNodeFactory(containingSymbol, statement.Syntax, compilationState, diagnostics); return (BoundStatement)new AsyncExceptionHandlerRewriter(containingSymbol, containingType, factory, awaitInFinallyAnalysis).Visit(statement); } public override BoundNode VisitTryStatement(BoundTryStatement node) { SyntaxNode syntax = node.Syntax; BoundStatement boundStatement; BoundBlock boundBlock; if (!_analysis.FinallyContainsAwaits(node)) { boundStatement = RewriteFinalizedRegion(node); boundBlock = (BoundBlock)Visit(node.FinallyBlockOpt); if (boundBlock == null) { return boundStatement; } if (boundStatement is BoundTryStatement boundTryStatement) { return boundTryStatement.Update(boundTryStatement.TryBlock, boundTryStatement.CatchBlocks, boundBlock, boundTryStatement.FinallyLabelOpt, boundTryStatement.PreferFaultHandler); } return _F.Try((BoundBlock)boundStatement, ImmutableArray.Empty, boundBlock); } AwaitFinallyFrame awaitFinallyFrame = PushFrame(node); boundStatement = RewriteFinalizedRegion(node); boundBlock = (BoundBlock)VisitBlock(node.FinallyBlockOpt); PopFrame(); NamedTypeSymbol typeSymbol = _F.SpecialType((SpecialType)1); SynthesizedLocal synthesizedLocal = new SynthesizedLocal(_F.CurrentFunction, TypeWithAnnotations.Create(typeSymbol), (SynthesizedLocalKind)22, syntax, isPinned: false, isKnownToReferToTempIfReferenceType: false, (RefKind)0); GeneratedLabelSymbol generatedLabelSymbol = _F.GenerateLabel("finallyLabel"); SynthesizedLocal synthesizedLocal2 = new SynthesizedLocal(_F.CurrentFunction, TypeWithAnnotations.Create(_F.SpecialType((SpecialType)13)), (SynthesizedLocalKind)23, syntax, isPinned: false, isKnownToReferToTempIfReferenceType: false, (RefKind)0); BoundCatchBlock item = _F.Catch(_F.Local(synthesizedLocal), _F.Block()); BoundStatement boundStatement2 = _F.Try(_F.Block(boundStatement, _F.HiddenSequencePoint(), _F.Goto(generatedLabelSymbol), PendBranches(awaitFinallyFrame, synthesizedLocal2, generatedLabelSymbol)), ImmutableArray.Create(item), null, generatedLabelSymbol); BoundBlock boundBlock2 = _F.Block(_F.HiddenSequencePoint(), _F.Label(generatedLabelSymbol), boundBlock, _F.HiddenSequencePoint(), UnpendException(synthesizedLocal), UnpendBranches(awaitFinallyFrame, synthesizedLocal2)); BoundStatement boundStatement3 = boundBlock2; if (_F.CurrentFunction.IsAsync && _F.CurrentFunction.IsIterator) { boundStatement3 = _F.ExtractedFinallyBlock(boundBlock2); } ArrayBuilder instance = ArrayBuilder.GetInstance(); ArrayBuilder instance2 = ArrayBuilder.GetInstance(); instance2.Add(_F.HiddenSequencePoint()); instance.Add((LocalSymbol)synthesizedLocal); instance2.Add((BoundStatement)_F.Assignment(_F.Local(synthesizedLocal), _F.Default(synthesizedLocal.Type))); instance.Add((LocalSymbol)synthesizedLocal2); instance2.Add((BoundStatement)_F.Assignment(_F.Local(synthesizedLocal2), _F.Default(synthesizedLocal2.Type))); LocalSymbol returnValue = awaitFinallyFrame.returnValue; if (returnValue != null) { instance.Add(returnValue); } instance2.Add(boundStatement2); instance2.Add(boundStatement3); return _F.Block(instance.ToImmutableAndFree(), instance2.ToImmutableAndFree()); } private BoundBlock PendBranches(AwaitFinallyFrame frame, LocalSymbol pendingBranchVar, LabelSymbol finallyLabel) { ArrayBuilder instance = ArrayBuilder.GetInstance(); List proxiedLabels = frame.proxiedLabels; Dictionary proxyLabels = frame.proxyLabels; int i = 1; if (proxiedLabels != null) { for (int count = proxiedLabels.Count; i <= count; i++) { LabelSymbol key = proxiedLabels[i - 1]; LabelSymbol proxy = proxyLabels[key]; PendBranch(instance, proxy, i, pendingBranchVar, finallyLabel); } } GeneratedLabelSymbol returnProxyLabel = frame.returnProxyLabel; if (returnProxyLabel != null) { PendBranch(instance, returnProxyLabel, i, pendingBranchVar, finallyLabel); } return _F.Block(instance.ToImmutableAndFree()); } private void PendBranch(ArrayBuilder bodyStatements, LabelSymbol proxy, int i, LocalSymbol pendingBranchVar, LabelSymbol finallyLabel) { bodyStatements.Add((BoundStatement)_F.Label(proxy)); bodyStatements.Add((BoundStatement)_F.Assignment(_F.Local(pendingBranchVar), _F.Literal(i))); bodyStatements.Add((BoundStatement)_F.Goto(finallyLabel)); } private BoundStatement UnpendBranches(AwaitFinallyFrame frame, SynthesizedLocal pendingBranchVar) { AwaitFinallyFrame parentOpt = frame.ParentOpt; List proxiedLabels = frame.proxiedLabels; int i = 1; ArrayBuilder instance = ArrayBuilder.GetInstance(); if (proxiedLabels != null) { for (int count = proxiedLabels.Count; i <= count; i++) { LabelSymbol label = proxiedLabels[i - 1]; LabelSymbol label2 = parentOpt.ProxyLabelIfNeeded(label); SyntheticBoundNodeFactory.SyntheticSwitchSection syntheticSwitchSection = _F.SwitchSection(i, _F.Goto(label2)); instance.Add(syntheticSwitchSection); } } if (frame.returnProxyLabel != null) { BoundLocal boundLocal = null; if (frame.returnValue != null) { boundLocal = _F.Local(frame.returnValue); } SynthesizedLocal returnValue; LabelSymbol labelSymbol = parentOpt.ProxyReturnIfNeeded(_F.CurrentFunction, boundLocal, out returnValue); BoundStatement boundStatement = ((labelSymbol == null) ? new BoundReturnStatement(_F.Syntax, (RefKind)0, boundLocal, @checked: false) : ((boundLocal != null) ? ((BoundStatement)_F.Block(_F.Assignment(_F.Local(returnValue), boundLocal), _F.Goto(labelSymbol))) : ((BoundStatement)_F.Goto(labelSymbol)))); SyntheticBoundNodeFactory.SyntheticSwitchSection syntheticSwitchSection2 = _F.SwitchSection(i, boundStatement); instance.Add(syntheticSwitchSection2); } return _F.Switch(_F.Local(pendingBranchVar), instance.ToImmutableAndFree()); } public override BoundNode VisitGotoStatement(BoundGotoStatement node) { BoundExpression caseExpressionOpt = (BoundExpression)Visit(node.CaseExpressionOpt); BoundLabel labelExpressionOpt = (BoundLabel)Visit(node.LabelExpressionOpt); LabelSymbol label = _currentAwaitFinallyFrame.ProxyLabelIfNeeded(node.Label); return node.Update(label, caseExpressionOpt, labelExpressionOpt); } public override BoundNode VisitConditionalGoto(BoundConditionalGoto node) { return base.VisitConditionalGoto(node); } public override BoundNode VisitReturnStatement(BoundReturnStatement node) { SynthesizedLocal returnValue; LabelSymbol labelSymbol = _currentAwaitFinallyFrame.ProxyReturnIfNeeded(_F.CurrentFunction, node.ExpressionOpt, out returnValue); if (labelSymbol == null) { return base.VisitReturnStatement(node); } BoundExpression boundExpression = (BoundExpression)Visit(node.ExpressionOpt); if (boundExpression != null) { return _F.Block(_F.Assignment(_F.Local(returnValue), boundExpression), _F.Goto(labelSymbol)); } return _F.Goto(labelSymbol); } private BoundStatement UnpendException(LocalSymbol pendingExceptionLocal) { LocalSymbol localSymbol = _F.SynthesizedLocal(_F.SpecialType((SpecialType)1), null, isPinned: false, isKnownToReferToTempIfReferenceType: false, (RefKind)0, (SynthesizedLocalKind)(-2)); BoundExpressionStatement boundExpressionStatement = _F.Assignment(_F.Local(localSymbol), _F.Local(pendingExceptionLocal)); BoundStatement thenClause = Rethrow(localSymbol); return _F.Block(ImmutableArray.Create(localSymbol), boundExpressionStatement, _F.If(_F.ObjectNotEqual(_F.Local(localSymbol), _F.Null(localSymbol.Type)), thenClause)); } private BoundStatement Rethrow(LocalSymbol obj) { BoundStatement boundStatement = _F.Throw(_F.Local(obj)); MethodSymbol methodSymbol = _F.WellKnownMethod((WellKnownMember)132, isOptional: true); MethodSymbol methodSymbol2 = _F.WellKnownMethod((WellKnownMember)133, isOptional: true); if (methodSymbol != null && methodSymbol2 != null) { LocalSymbol localSymbol = _F.SynthesizedLocal(_F.WellKnownType((WellKnownType)52), null, isPinned: false, isKnownToReferToTempIfReferenceType: false, (RefKind)0, (SynthesizedLocalKind)(-2)); BoundExpressionStatement boundExpressionStatement = _F.Assignment(_F.Local(localSymbol), _F.As(_F.Local(obj), localSymbol.Type)); boundStatement = _F.Block(ImmutableArray.Create(localSymbol), boundExpressionStatement, _F.If(_F.ObjectEqual(_F.Local(localSymbol), _F.Null(localSymbol.Type)), boundStatement), _F.ExpressionStatement(_F.Call(_F.StaticCall(methodSymbol.ContainingType, methodSymbol, _F.Local(localSymbol)), methodSymbol2))); } return boundStatement; } private BoundStatement RewriteFinalizedRegion(BoundTryStatement node) { BoundBlock boundBlock = (BoundBlock)VisitBlock(node.TryBlock); if (node.CatchBlocks.IsDefaultOrEmpty) { return boundBlock; } AwaitCatchFrame currentAwaitCatchFrame = _currentAwaitCatchFrame; _currentAwaitCatchFrame = null; ImmutableArray catchBlocks = ImmutableArrayExtensions.SelectAsArray(node.CatchBlocks, (Func)delegate(BoundCatchBlock catchBlock, (AsyncExceptionHandlerRewriter, AwaitCatchFrame origAwaitCatchFrame) arg) { var (asyncExceptionHandlerRewriter, parentAwaitCatchFrame) = arg; return (BoundCatchBlock)asyncExceptionHandlerRewriter.VisitCatchBlock(catchBlock, parentAwaitCatchFrame); }, (this, currentAwaitCatchFrame)); BoundStatement boundStatement = _F.Try(boundBlock, catchBlocks); AwaitCatchFrame currentAwaitCatchFrame2 = _currentAwaitCatchFrame; if (currentAwaitCatchFrame2 != null) { GeneratedLabelSymbol label = _F.GenerateLabel("handled"); List handlers = currentAwaitCatchFrame2.handlers; ArrayBuilder instance = ArrayBuilder.GetInstance(handlers.Count); int num = 0; for (int count = handlers.Count; num < count; num++) { instance.Add(_F.SwitchSection(num + 1, _F.Block(handlers[num], _F.Goto(label)))); } boundStatement = _F.Block(ImmutableArray.Create((LocalSymbol)currentAwaitCatchFrame2.pendingCaughtException, (LocalSymbol)currentAwaitCatchFrame2.pendingCatch).AddRange(currentAwaitCatchFrame2.GetHoistedLocals()), _F.HiddenSequencePoint(), _F.Assignment(_F.Local(currentAwaitCatchFrame2.pendingCatch), _F.Default(currentAwaitCatchFrame2.pendingCatch.Type)), boundStatement, _F.HiddenSequencePoint(), _F.Switch(_F.Local(currentAwaitCatchFrame2.pendingCatch), instance.ToImmutableAndFree()), _F.HiddenSequencePoint(), _F.Label(label)); } _currentAwaitCatchFrame = currentAwaitCatchFrame; return boundStatement; } public override BoundNode VisitCatchBlock(BoundCatchBlock node) { throw ExceptionUtilities.Unreachable("/_/src/Compilers/CSharp/Portable/Lowering/AsyncRewriter/AsyncExceptionHandlerRewriter.cs", 511); } private BoundNode VisitCatchBlock(BoundCatchBlock node, AwaitCatchFrame parentAwaitCatchFrame) { if (!_analysis.CatchContainsAwait(node)) { AwaitCatchFrame currentAwaitCatchFrame = _currentAwaitCatchFrame; _currentAwaitCatchFrame = null; BoundNode? result = base.VisitCatchBlock(node); _currentAwaitCatchFrame = currentAwaitCatchFrame; return result; } AwaitCatchFrame awaitCatchFrame = _currentAwaitCatchFrame; if (awaitCatchFrame == null) { TryStatementSyntax tryStatementSyntax = (TryStatementSyntax)(object)node.Syntax.Parent; awaitCatchFrame = (_currentAwaitCatchFrame = new AwaitCatchFrame(_F, tryStatementSyntax, parentAwaitCatchFrame)); } TypeSymbol typeSymbol = node.ExceptionTypeOpt ?? _F.SpecialType((SpecialType)1); LocalSymbol localSymbol = _F.SynthesizedLocal(typeSymbol, null, isPinned: false, isKnownToReferToTempIfReferenceType: false, (RefKind)0, (SynthesizedLocalKind)(-2)); BoundExpression expr = _F.AssignmentExpression(_F.Local(awaitCatchFrame.pendingCaughtException), _F.Convert(awaitCatchFrame.pendingCaughtException.Type, _F.Local(localSymbol))); BoundExpressionStatement boundExpressionStatement = _F.Assignment(_F.Local(awaitCatchFrame.pendingCatch), _F.Literal(awaitCatchFrame.handlers.Count + 1)); BoundStatementList exceptionFilterPrologueOpt = node.ExceptionFilterPrologueOpt; BoundExpression exceptionFilterOpt = node.ExceptionFilterOpt; BoundCatchBlock result2; ImmutableArray locals; if (exceptionFilterOpt == null) { result2 = node.Update(ImmutableArray.Create(localSymbol), _F.Local(localSymbol), typeSymbol, exceptionFilterPrologueOpt, null, _F.Block(_F.HiddenSequencePoint(), _F.ExpressionStatement(expr), boundExpressionStatement), node.IsSynthesizedAsyncCatchAll); locals = node.Locals; } else { locals = ImmutableArray.Empty; ImmutableArray.Enumerator enumerator = node.Locals.GetEnumerator(); while (enumerator.MoveNext()) { LocalSymbol current = enumerator.Current; awaitCatchFrame.HoistLocal(current, _F); } BoundStatementList boundStatementList = (BoundStatementList)Visit(exceptionFilterPrologueOpt); ArrayBuilder instance = ArrayBuilder.GetInstance(); BoundExpression exceptionSourceOpt = node.ExceptionSourceOpt; instance.Add((BoundStatement)_F.ExpressionStatement(expr)); if (exceptionSourceOpt != null) { instance.Add((BoundStatement)_F.ExpressionStatement(AssignCatchSource((BoundExpression)Visit(exceptionSourceOpt), awaitCatchFrame))); } if (boundStatementList != null) { instance.Add((BoundStatement)boundStatementList); } BoundStatementList exceptionFilterPrologueOpt2 = _F.StatementList(instance.ToImmutableAndFree()); BoundExpression exceptionFilterOpt2 = (BoundExpression)Visit(exceptionFilterOpt); result2 = node.Update(ImmutableArray.Create(localSymbol), _F.Local(localSymbol), typeSymbol, exceptionFilterPrologueOpt2, exceptionFilterOpt2, _F.Block(_F.HiddenSequencePoint(), boundExpressionStatement), node.IsSynthesizedAsyncCatchAll); } ArrayBuilder instance2 = ArrayBuilder.GetInstance(); instance2.Add(_F.HiddenSequencePoint()); if (exceptionFilterOpt == null) { BoundExpression exceptionSourceOpt2 = node.ExceptionSourceOpt; if (exceptionSourceOpt2 != null) { BoundExpression expr2 = AssignCatchSource((BoundExpression)Visit(exceptionSourceOpt2), awaitCatchFrame); instance2.Add((BoundStatement)_F.ExpressionStatement(expr2)); } } instance2.Add((BoundStatement)Visit(node.Body)); BoundBlock item = _F.Block(locals, instance2.ToImmutableAndFree()); awaitCatchFrame.handlers.Add(item); return result2; } private BoundExpression AssignCatchSource(BoundExpression rewrittenSource, AwaitCatchFrame currentAwaitCatchFrame) { BoundExpression result = null; if (rewrittenSource != null) { result = _F.AssignmentExpression(rewrittenSource, _F.Convert(rewrittenSource.Type, _F.Local(currentAwaitCatchFrame.pendingCaughtException))); } return result; } public override BoundNode VisitLocal(BoundLocal node) { AwaitCatchFrame currentAwaitCatchFrame = _currentAwaitCatchFrame; if (currentAwaitCatchFrame == null || !currentAwaitCatchFrame.TryGetHoistedLocal(node.LocalSymbol, out var hoistedLocal)) { return base.VisitLocal(node); } return node.Update(hoistedLocal, node.ConstantValueOpt, hoistedLocal.Type); } public override BoundNode VisitThrowStatement(BoundThrowStatement node) { if (node.ExpressionOpt != null || _currentAwaitCatchFrame == null) { return base.VisitThrowStatement(node); } return Rethrow(_currentAwaitCatchFrame.pendingCaughtException); } public override BoundNode VisitLambda(BoundLambda node) { MethodSymbol currentFunction = _F.CurrentFunction; AwaitFinallyFrame currentAwaitFinallyFrame = _currentAwaitFinallyFrame; _F.CurrentFunction = node.Symbol; _currentAwaitFinallyFrame = new AwaitFinallyFrame(); BoundNode? result = base.VisitLambda(node); _F.CurrentFunction = currentFunction; _currentAwaitFinallyFrame = currentAwaitFinallyFrame; return result; } public override BoundNode VisitLocalFunctionStatement(BoundLocalFunctionStatement node) { MethodSymbol currentFunction = _F.CurrentFunction; AwaitFinallyFrame currentAwaitFinallyFrame = _currentAwaitFinallyFrame; _F.CurrentFunction = node.Symbol; _currentAwaitFinallyFrame = new AwaitFinallyFrame(); BoundNode? result = base.VisitLocalFunctionStatement(node); _F.CurrentFunction = currentFunction; _currentAwaitFinallyFrame = currentAwaitFinallyFrame; return result; } private AwaitFinallyFrame PushFrame(BoundTryStatement statement) { return _currentAwaitFinallyFrame = new AwaitFinallyFrame(_currentAwaitFinallyFrame, _analysis.Labels(statement), statement.Syntax); } private void PopFrame() { AwaitFinallyFrame currentAwaitFinallyFrame = _currentAwaitFinallyFrame; _currentAwaitFinallyFrame = currentAwaitFinallyFrame.ParentOpt; } }