File: Lowering\LocalRewriter\LocalRewriter_Await.cs
Web Access
Project: src\src\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj (Microsoft.CodeAnalysis.CSharp)
// 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.Collections.Immutable;
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.CSharp.Symbols;
 
namespace Microsoft.CodeAnalysis.CSharp
{
    internal sealed partial class LocalRewriter
    {
        public override BoundNode VisitAwaitExpression(BoundAwaitExpression node)
        {
            return VisitAwaitExpression(node, true);
        }
 
        public BoundExpression VisitAwaitExpression(BoundAwaitExpression node, bool used)
        {
            return RewriteAwaitExpression((BoundExpression)base.VisitAwaitExpression(node)!, used);
        }
 
        private BoundExpression RewriteAwaitExpression(SyntaxNode syntax, BoundExpression rewrittenExpression, BoundAwaitableInfo awaitableInfo, TypeSymbol type, BoundAwaitExpressionDebugInfo debugInfo, bool used)
        {
            return RewriteAwaitExpression(new BoundAwaitExpression(syntax, rewrittenExpression, awaitableInfo, debugInfo, type) { WasCompilerGenerated = true }, used);
        }
 
        /// <summary>
        /// Lower an await expression that has already had its components rewritten.
        /// </summary>
        private BoundExpression RewriteAwaitExpression(BoundExpression rewrittenAwait, bool used)
        {
            _sawAwait = true;
            if (!used)
            {
                // Await expression is already at the statement level.
                return rewrittenAwait;
            }
 
            // The await expression will be lowered to code that involves the use of side-effects
            // such as jumps and labels, which we can only emit with an empty stack, so we require
            // that the await expression itself is produced only when the stack is empty.
            // Therefore it is represented by a BoundSpillSequence.  The resulting nodes will be "spilled" to move
            // such statements to the top level (i.e. into the enclosing statement list).  Here we ensure
            // that the await result itself is stored into a temp at the statement level, as that is
            // the form handled by async lowering.
            _needsSpilling = true;
            var tempAccess = _factory.StoreToTemp(rewrittenAwait, out BoundAssignmentOperator tempAssignment, syntaxOpt: rewrittenAwait.Syntax,
                kind: SynthesizedLocalKind.Spill);
            return new BoundSpillSequence(
                syntax: rewrittenAwait.Syntax,
                locals: ImmutableArray.Create<LocalSymbol>(tempAccess.LocalSymbol),
                sideEffects: ImmutableArray.Create<BoundExpression>(tempAssignment),
                value: tempAccess,
                type: tempAccess.Type);
        }
    }
}