Esempio n. 1
0
        public override BoundNode VisitAwaitExpression(BoundAwaitExpression node)
        {
            var ss          = new BoundSpillSequence2();
            var replacement = VisitExpression(ref ss, node);

            return(ss.Update(replacement));
        }
Esempio n. 2
0
        public override BoundNode VisitAwaitExpression(BoundAwaitExpression node)
        {
            var builder     = new BoundSpillSequenceBuilder();
            var replacement = VisitExpression(ref builder, node);

            return(builder.Update(replacement));
        }
        private BoundBlock VisitAwaitExpression(BoundAwaitExpression node, BoundExpression resultPlace)
        {
            var expression           = (BoundExpression)Visit(node.Expression);
            var awaitablePlaceholder = node.AwaitableInfo.AwaitableInstancePlaceholder;

            if (awaitablePlaceholder != null)
            {
                _placeholderMap.Add(awaitablePlaceholder, expression);
            }

            var getAwaiter = node.AwaitableInfo.IsDynamic ?
                             MakeCallMaybeDynamic(expression, null, WellKnownMemberNames.GetAwaiter) :
                             (BoundExpression)Visit(node.AwaitableInfo.GetAwaiter);

            resultPlace = (BoundExpression)Visit(resultPlace);
            MethodSymbol getResult         = VisitMethodSymbol(node.AwaitableInfo.GetResult);
            MethodSymbol isCompletedMethod = ((object)node.AwaitableInfo.IsCompleted != null) ? VisitMethodSymbol(node.AwaitableInfo.IsCompleted.GetMethod) : null;
            TypeSymbol   type = VisitType(node.Type);

            if (awaitablePlaceholder != null)
            {
                _placeholderMap.Remove(awaitablePlaceholder);
            }

            // The awaiter temp facilitates EnC method remapping and thus have to be long-lived.
            // It transfers the awaiter objects from the old version of the MoveNext method to the new one.
            Debug.Assert(node.Syntax.IsKind(SyntaxKind.AwaitExpression) || node.WasCompilerGenerated);

            var awaiterTemp       = F.SynthesizedLocal(getAwaiter.Type, syntax: node.Syntax, kind: SynthesizedLocalKind.Awaiter);
            var awaitIfIncomplete = F.Block(
                // temp $awaiterTemp = <expr>.GetAwaiter();
                F.Assignment(
                    F.Local(awaiterTemp),
                    getAwaiter),

                // hidden sequence point facilitates EnC method remapping, see explanation on SynthesizedLocalKind.Awaiter:
                F.HiddenSequencePoint(),

                // if(!($awaiterTemp.IsCompleted)) { ... }
                F.If(
                    condition: F.Not(GenerateGetIsCompleted(awaiterTemp, isCompletedMethod)),
                    thenClause: GenerateAwaitForIncompleteTask(awaiterTemp)));
            BoundExpression getResultCall = MakeCallMaybeDynamic(
                F.Local(awaiterTemp),
                getResult,
                WellKnownMemberNames.GetResult,
                resultsDiscarded: resultPlace == null);

            // [$resultPlace = ] $awaiterTemp.GetResult();
            BoundStatement getResultStatement = resultPlace != null && !type.IsVoidType() ?
                                                F.Assignment(resultPlace, getResultCall) :
                                                F.ExpressionStatement(getResultCall);

            return(F.Block(
                       ImmutableArray.Create(awaiterTemp),
                       awaitIfIncomplete,
                       getResultStatement));
        }
Esempio n. 4
0
        private BoundBlock VisitAwaitExpression(BoundAwaitExpression node, BoundExpression resultPlace)
        {
            var expression = (BoundExpression)Visit(node.Expression);

            resultPlace = (BoundExpression)Visit(resultPlace);
            MethodSymbol getAwaiter        = VisitMethodSymbol(node.GetAwaiter);
            MethodSymbol getResult         = VisitMethodSymbol(node.GetResult);
            MethodSymbol isCompletedMethod = ((object)node.IsCompleted != null) ? VisitMethodSymbol(node.IsCompleted.GetMethod) : null;
            TypeSymbol   type = VisitType(node.Type);

            // The lifespan of awaiter temp doesn't cross sequence points (user code in between awaits), so it doesn't need to be named.
            TypeSymbol awaiterType = node.IsDynamic ? DynamicTypeSymbol.Instance : getAwaiter.ReturnType;
            var        awaiterTemp = F.SynthesizedLocal(awaiterType);

            var awaitIfIncomplete = F.Block(
                // temp $awaiterTemp = <expr>.GetAwaiter();
                F.Assignment(
                    F.Local(awaiterTemp),
                    MakeCallMaybeDynamic(expression, getAwaiter, WellKnownMemberNames.GetAwaiter)),

                // if(!($awaiterTemp.IsCompleted)) { ... }
                F.If(
                    condition: F.Not(GenerateGetIsCompleted(awaiterTemp, isCompletedMethod)),
                    thenClause: GenerateAwaitForIncompleteTask(awaiterTemp)));

            BoundExpression getResultCall = MakeCallMaybeDynamic(
                F.Local(awaiterTemp),
                getResult,
                WellKnownMemberNames.GetResult,
                resultsDiscarded: resultPlace == null);

            var nullAwaiter = F.AssignmentExpression(F.Local(awaiterTemp), F.NullOrDefault(awaiterTemp.Type));

            if (resultPlace != null && type.SpecialType != SpecialType.System_Void)
            {
                // $resultTemp = $awaiterTemp.GetResult();
                // $awaiterTemp = null;
                // $resultTemp
                LocalSymbol resultTemp = F.SynthesizedLocal(type);
                return(F.Block(
                           ImmutableArray.Create(awaiterTemp, resultTemp),
                           awaitIfIncomplete,
                           F.Assignment(F.Local(resultTemp), getResultCall),
                           F.ExpressionStatement(nullAwaiter),
                           F.Assignment(resultPlace, F.Local(resultTemp))));
            }
            else
            {
                // $awaiterTemp.GetResult();
                // $awaiterTemp = null;
                return(F.Block(
                           ImmutableArray.Create(awaiterTemp),
                           awaitIfIncomplete,
                           F.ExpressionStatement(getResultCall),
                           F.ExpressionStatement(nullAwaiter)));
            }
        }
Esempio n. 5
0
        public override BoundNode VisitAwaitExpression(BoundAwaitExpression node)
        {
            // An await expression has already been wrapped in a BoundSpillSequence if not at the top level, so
            // the spilling will occur in the enclosing node.
            BoundSpillSequenceBuilder builder = null;
            var expr = VisitExpression(ref builder, node.Expression);

            return(UpdateExpression(builder, node.Update(expr, node.AwaitableInfo, node.Type)));
        }
Esempio n. 6
0
        public override BoundNode VisitAwaitExpression(BoundAwaitExpression node)
        {
            if (this.ExceptionHandleNesting != 0)
            {
                Debug.Assert(this.ExceptionHandleNesting > 0);
                this.sawAwaitInExceptionHandler = true;
            }

            return(base.VisitAwaitExpression(node));
        }
Esempio n. 7
0
        public override BoundNode VisitAwaitExpression(BoundAwaitExpression node)
        {
            if (this.ExceptionHandleNesting != 0)
            {
                Debug.Assert(this.ExceptionHandleNesting > 0);
                this.sawAwaitInExceptionHandler = true;
            }

            return base.VisitAwaitExpression(node);
        }
 public override BoundNode VisitAwaitExpression(BoundAwaitExpression node)
 {
     return(VisitAwaitExpression(node, resultsDiscarded: false));
 }
 public override BoundNode VisitAwaitExpression(BoundAwaitExpression node)
 {
     // await expressions must, by now, have been moved to the top level.
     throw ExceptionUtilities.Unreachable;
 }
            private BoundExpression VisitAwaitExpression(BoundAwaitExpression node, bool resultsDiscarded)
            {
                var expression = (BoundExpression)Visit(node.Expression);

                MethodSymbol getAwaiter        = VisitMethodSymbol(node.GetAwaiter);
                MethodSymbol getResult         = VisitMethodSymbol(node.GetResult);
                MethodSymbol isCompletedMethod = (node.IsCompleted != null) ? VisitMethodSymbol(node.IsCompleted.GetMethod) : null;
                TypeSymbol   type = VisitType(node.Type);

                LocalSymbol awaiterTemp;

                if (getResult == null)
                {
                    awaiterTemp = F.SynthesizedLocal(DynamicTypeSymbol.Instance, name: null);
                }
                else if (type.IsDynamic())
                {
                    var awaiterType = ((NamedTypeSymbol)getAwaiter.ReturnType).OriginalNamedTypeDefinition.Construct(F.SpecialType(SpecialType.System_Object));
                    awaiterTemp       = F.SynthesizedLocal(awaiterType, null);
                    getResult         = ((MethodSymbol)getResult.OriginalDefinition).AsMember(awaiterType);
                    isCompletedMethod = ((MethodSymbol)isCompletedMethod.OriginalDefinition).AsMember(awaiterType);
                }
                else
                {
                    awaiterTemp = F.SynthesizedLocal(getAwaiter.ReturnType, name: null);
                }

                var awaitIfIncomplete = F.Block(
                    // temp $awaiterTemp = <expr>.GetAwaiter();
                    F.Assignment(
                        F.Local(awaiterTemp),
                        MakeCallMaybeDynamic(expression, getAwaiter, "GetAwaiter")),

                    // if(!($awaiterTemp.IsCompleted)) { ... }
                    F.If(
                        condition: F.Not(GenerateGetIsCompleted(awaiterTemp, isCompletedMethod)),
                        thenClause: GenerateAwaitForIncompleteTask(awaiterTemp)));

                BoundExpression getResultCall = MakeCallMaybeDynamic(
                    F.Local(awaiterTemp),
                    getResult,
                    "GetResult",
                    resultsDiscarded: resultsDiscarded);

                var nullAwaiter = F.AssignmentExpression(F.Local(awaiterTemp), F.NullOrDefault(awaiterTemp.Type));

                BoundExpression onAwaitFinished;

                if (!resultsDiscarded && type.SpecialType != SpecialType.System_Void)
                {
                    // $resultTemp = $awaiterTemp.GetResult();
                    // $awaiterTemp = null;
                    // $resultTemp
                    LocalSymbol resultTemp = F.SynthesizedLocal(type, null);
                    onAwaitFinished = F.Sequence(
                        resultTemp,
                        F.AssignmentExpression(F.Local(resultTemp), getResultCall),
                        nullAwaiter,
                        F.Local(resultTemp));
                }
                else
                {
                    // $awaiterTemp.GetResult();
                    // $awaiterTemp = null;
                    onAwaitFinished = F.Sequence(
                        ReadOnlyArray <LocalSymbol> .Empty,
                        getResultCall,
                        nullAwaiter);
                }

                return(F.SpillSequence(
                           ReadOnlyArray <LocalSymbol> .CreateFrom(awaiterTemp),
                           ReadOnlyArray <BoundSpillTemp> .Empty,
                           ReadOnlyArray <FieldSymbol> .Empty,
                           ReadOnlyArray <BoundStatement> .CreateFrom(awaitIfIncomplete),
                           onAwaitFinished));
            }
 public override BoundNode VisitAwaitExpression(BoundAwaitExpression node)
 {
     base.VisitAwaitExpression(node);
     MarkLocalsUnassigned();
     return null;
 }
Esempio n. 12
0
 public override BoundNode VisitAwaitExpression(BoundAwaitExpression node)
 {
     return VisitAwaitExpression(node, resultsDiscarded: false);
 }
Esempio n. 13
0
            private BoundExpression VisitAwaitExpression(BoundAwaitExpression node, bool resultsDiscarded)
            {
                var expression = (BoundExpression)Visit(node.Expression);

                MethodSymbol getAwaiter = VisitMethodSymbol(node.GetAwaiter);
                MethodSymbol getResult = VisitMethodSymbol(node.GetResult);
                MethodSymbol isCompletedMethod = (node.IsCompleted != null) ? VisitMethodSymbol(node.IsCompleted.GetMethod) : null;
                TypeSymbol type = VisitType(node.Type);

                LocalSymbol awaiterTemp;
                if (getResult == null)
                {
                    awaiterTemp = F.SynthesizedLocal(DynamicTypeSymbol.Instance, name: null);
                }
                else if (type.IsDynamic())
                {
                    var awaiterType = ((NamedTypeSymbol)getAwaiter.ReturnType).OriginalNamedTypeDefinition.Construct(F.SpecialType(SpecialType.System_Object));
                    awaiterTemp = F.SynthesizedLocal(awaiterType, null);
                    getResult = ((MethodSymbol)getResult.OriginalDefinition).AsMember(awaiterType);
                    isCompletedMethod = ((MethodSymbol)isCompletedMethod.OriginalDefinition).AsMember(awaiterType);
                }
                else
                {
                    awaiterTemp = F.SynthesizedLocal(getAwaiter.ReturnType, name: null);
                }

                var awaitIfIncomplete = F.Block(
                    // temp $awaiterTemp = <expr>.GetAwaiter();
                    F.Assignment(
                        F.Local(awaiterTemp),
                        MakeCallMaybeDynamic(expression, getAwaiter, "GetAwaiter")),

                    // if(!($awaiterTemp.IsCompleted)) { ... }
                    F.If(
                        condition: F.Not(GenerateGetIsCompleted(awaiterTemp, isCompletedMethod)),
                        thenClause: GenerateAwaitForIncompleteTask(awaiterTemp)));

                BoundExpression getResultCall = MakeCallMaybeDynamic(
                    F.Local(awaiterTemp),
                    getResult,
                    "GetResult",
                    resultsDiscarded: resultsDiscarded);

                var nullAwaiter = F.AssignmentExpression(F.Local(awaiterTemp), F.NullOrDefault(awaiterTemp.Type));
                
                BoundExpression onAwaitFinished;
                if (!resultsDiscarded && type.SpecialType != SpecialType.System_Void)
                {
                    // $resultTemp = $awaiterTemp.GetResult();
                    // $awaiterTemp = null;
                    // $resultTemp
                    LocalSymbol resultTemp = F.SynthesizedLocal(type, null);
                    onAwaitFinished = F.Sequence(
                        resultTemp,
                        F.AssignmentExpression(F.Local(resultTemp), getResultCall),
                        nullAwaiter,
                        F.Local(resultTemp));
                }
                else
                {
                    // $awaiterTemp.GetResult();
                    // $awaiterTemp = null;
                    onAwaitFinished = F.Sequence(
                        ReadOnlyArray<LocalSymbol>.Empty,
                        getResultCall,
                        nullAwaiter);
                }

                return F.SpillSequence(
                    ReadOnlyArray<LocalSymbol>.CreateFrom(awaiterTemp),
                    ReadOnlyArray<BoundSpillTemp>.Empty,
                    ReadOnlyArray<FieldSymbol>.Empty,
                    ReadOnlyArray<BoundStatement>.CreateFrom(awaitIfIncomplete),
                    onAwaitFinished);
            }
        private BoundStatement RewriteUsingStatementTryFinally(SyntaxNode syntax, BoundBlock tryBlock, BoundLocal local, SyntaxToken awaitKeywordOpt, AwaitableInfo awaitOpt)
        {
            // SPEC: When ResourceType is a non-nullable value type, the expansion is:
            // SPEC:
            // SPEC: {
            // SPEC:   ResourceType resource = expr;
            // SPEC:   try { statement; }
            // SPEC:   finally { ((IDisposable)resource).Dispose(); }
            // SPEC: }
            // SPEC:
            // SPEC: Otherwise, when Resource type is a nullable value type or
            // SPEC: a reference type other than dynamic, the expansion is:
            // SPEC:
            // SPEC: {
            // SPEC:   ResourceType resource = expr;
            // SPEC:   try { statement; }
            // SPEC:   finally { if (resource != null) ((IDisposable)resource).Dispose(); }
            // SPEC: }
            // SPEC:
            // SPEC: Otherwise, when ResourceType is dynamic, the expansion is:
            // SPEC: {
            // SPEC:   dynamic resource = expr;
            // SPEC:   IDisposable d = (IDisposable)resource;
            // SPEC:   try { statement; }
            // SPEC:   finally { if (d != null) d.Dispose(); }
            // SPEC: }
            // SPEC:
            // SPEC: An implementation is permitted to implement a given using statement
            // SPEC: differently -- for example, for performance reasons -- as long as the
            // SPEC: behavior is consistent with the above expansion.
            //
            // In the case of using-await statement, we'll use "IAsyncDisposable" instead of "IDisposable", "await DisposeAsync()" instead of "Dispose()"
            //
            // And we do in fact generate the code slightly differently than precisely how it is
            // described above.
            //
            // First: if the type is a non-nullable value type then we do not do the
            // *boxing conversion* from the resource to IDisposable. Rather, we do
            // a *constrained virtual call* that elides the boxing if possible.
            //
            // Now, you might wonder if that is legal; isn't skipping the boxing producing
            // an observable difference? Because if the value type is mutable and the Dispose
            // mutates it, then skipping the boxing means that we are now mutating the original,
            // not the boxed copy. But this is never observable. Either (1) we have "using(R r = x){}"
            // and r is out of scope after the finally, so it is not possible to observe the mutation,
            // or (2) we have "using(x) {}". But that has the semantics of "using(R temp = x){}",
            // so again, we are not mutating x to begin with; we're always mutating a copy. Therefore
            // it doesn't matter if we skip making *a copy of the copy*.
            //
            // This is what the dev10 compiler does, and we do so as well.
            //
            // Second: if the type is a nullable value type then we can similarly elide the boxing.
            // We can generate
            //
            // {
            //   ResourceType resource = expr;
            //   try { statement; }
            //   finally { if (resource.HasValue) resource.GetValueOrDefault().Dispose(); }
            // }
            //
            // Where again we do a constrained virtual call to Dispose, rather than boxing
            // the value to IDisposable.
            //
            // Note that this optimization is *not* what the native compiler does; in this case
            // the native compiler behavior is to test for HasValue, then *box* and convert
            // the boxed value to IDisposable. There's no need to do that.
            //
            // Third: if we have "using(x)" and x is dynamic then obviously we need not generate
            // "{ dynamic temp1 = x; IDisposable temp2 = (IDisposable) temp1; ... }". Rather, we elide
            // the completely unnecessary first temporary.

            Debug.Assert((awaitKeywordOpt == default) == (awaitOpt == default(AwaitableInfo)));
            BoundExpression disposedExpression;
            bool            isNullableValueType = local.Type.IsNullableType();

            if (isNullableValueType)
            {
                MethodSymbol getValueOrDefault = UnsafeGetNullableMethod(syntax, local.Type, SpecialMember.System_Nullable_T_GetValueOrDefault);
                // local.GetValueOrDefault()
                disposedExpression = BoundCall.Synthesized(syntax, local, getValueOrDefault);
            }
            else
            {
                // local
                disposedExpression = local;
            }

            BoundExpression disposeCall;

            if (awaitOpt == null && Binder.TryGetSpecialTypeMember(_compilation, SpecialMember.System_IDisposable__Dispose, syntax, _diagnostics, out MethodSymbol disposeMethodSymbol))
            {
                // local.Dispose()
                disposeCall = BoundCall.Synthesized(syntax, disposedExpression, disposeMethodSymbol);
            }
            else if (awaitOpt != null &&
                     TryGetWellKnownTypeMember(syntax: null, WellKnownMember.System_IAsyncDisposable__DisposeAsync,
                                               out MethodSymbol disposeAsyncMethodSymbol, location: awaitKeywordOpt.GetLocation()))
            {
                // await local.DisposeAsync()
                _sawAwaitInExceptionHandler = true;
                var callExpr = BoundCall.Synthesized(syntax, disposedExpression, disposeAsyncMethodSymbol);

                TypeSymbol           awaitExpressionType = awaitOpt.GetResult?.ReturnType.TypeSymbol ?? _compilation.DynamicType;
                BoundAwaitExpression awaitExpr           = new BoundAwaitExpression(syntax, callExpr, awaitOpt, awaitExpressionType)
                {
                    WasCompilerGenerated = true
                };
                disposeCall = (BoundExpression)VisitAwaitExpression(awaitExpr);
            }
 public override BoundNode VisitAwaitExpression(BoundAwaitExpression node)
 {
     _seenAwait = true;
     return base.VisitAwaitExpression(node);
 }
        private BoundBlock VisitAwaitExpression(BoundAwaitExpression node, BoundExpression resultPlace)
        {
            var expression = (BoundExpression)Visit(node.Expression);

            resultPlace = (BoundExpression)Visit(resultPlace);
            MethodSymbol getAwaiter        = VisitMethodSymbol(node.GetAwaiter);
            MethodSymbol getResult         = VisitMethodSymbol(node.GetResult);
            MethodSymbol isCompletedMethod = ((object)node.IsCompleted != null) ? VisitMethodSymbol(node.IsCompleted.GetMethod) : null;
            TypeSymbol   type = VisitType(node.Type);

            // The awaiter temp facilitates EnC method remapping and thus have to be long-lived.
            // It transfers the awaiter objects from the old version of the MoveNext method to the new one.
            Debug.Assert(node.Syntax.IsKind(SyntaxKind.AwaitExpression));
            TypeSymbol awaiterType = node.IsDynamic ? DynamicTypeSymbol.Instance : getAwaiter.ReturnType;
            var        awaiterTemp = F.SynthesizedLocal(awaiterType, syntax: node.Syntax, kind: SynthesizedLocalKind.Awaiter);

            var awaitIfIncomplete = F.Block(
                // temp $awaiterTemp = <expr>.GetAwaiter();
                F.Assignment(
                    F.Local(awaiterTemp),
                    MakeCallMaybeDynamic(expression, getAwaiter, WellKnownMemberNames.GetAwaiter)),

                // hidden sequence point facilitates EnC method remapping, see explanation on SynthesizedLocalKind.Awaiter:
                F.HiddenSequencePoint(),

                // if(!($awaiterTemp.IsCompleted)) { ... }
                F.If(
                    condition: F.Not(GenerateGetIsCompleted(awaiterTemp, isCompletedMethod)),
                    thenClause: GenerateAwaitForIncompleteTask(awaiterTemp)));

            BoundExpression getResultCall = MakeCallMaybeDynamic(
                F.Local(awaiterTemp),
                getResult,
                WellKnownMemberNames.GetResult,
                resultsDiscarded: resultPlace == null);

            var nullAwaiter = F.AssignmentExpression(F.Local(awaiterTemp), F.NullOrDefault(awaiterTemp.Type));

            if (resultPlace != null && type.SpecialType != SpecialType.System_Void)
            {
                // $resultTemp = $awaiterTemp.GetResult();
                // $awaiterTemp = null;
                // $resultTemp
                LocalSymbol resultTemp = F.SynthesizedLocal(type);
                return(F.Block(
                           ImmutableArray.Create(awaiterTemp, resultTemp),
                           awaitIfIncomplete,
                           F.Assignment(F.Local(resultTemp), getResultCall),
                           F.ExpressionStatement(nullAwaiter),
                           F.Assignment(resultPlace, F.Local(resultTemp))));
            }
            else
            {
                // $awaiterTemp.GetResult();
                // $awaiterTemp = null;
                return(F.Block(
                           ImmutableArray.Create(awaiterTemp),
                           awaitIfIncomplete,
                           F.ExpressionStatement(getResultCall),
                           F.ExpressionStatement(nullAwaiter)));
            }
        }
 public override BoundNode VisitAwaitExpression(BoundAwaitExpression node)
 {
     _seenAwait = true;
     return(base.VisitAwaitExpression(node));
 }
Esempio n. 18
0
 public override BoundNode VisitAwaitExpression(BoundAwaitExpression node)
 {
     var ss = new BoundSpillSequence2();
     var replacement = VisitExpression(ref ss, node);
     return ss.Update(replacement);
 }
Esempio n. 19
0
 public BoundExpression VisitAwaitExpression(BoundAwaitExpression node, bool used)
 {
     return(RewriteAwaitExpression((BoundExpression)base.VisitAwaitExpression(node) !, used));
 }
Esempio n. 20
0
 public override BoundNode VisitAwaitExpression(BoundAwaitExpression node)
 {
     return(VisitAwaitExpression(node, true));
 }
            private BoundBlock VisitAwaitExpression(BoundAwaitExpression node, BoundExpression resultPlace)
            {
                var expression = (BoundExpression)Visit(node.Expression);

                resultPlace = (BoundExpression)Visit(resultPlace);
                MethodSymbol getAwaiter        = VisitMethodSymbol(node.GetAwaiter);
                MethodSymbol getResult         = VisitMethodSymbol(node.GetResult);
                MethodSymbol isCompletedMethod = ((object)node.IsCompleted != null) ? VisitMethodSymbol(node.IsCompleted.GetMethod) : null;
                TypeSymbol   type = VisitType(node.Type);

                LocalSymbol awaiterTemp;

                if ((object)getResult == null)
                {
                    awaiterTemp = F.SynthesizedLocal(DynamicTypeSymbol.Instance);
                }
                else if (type.IsDynamic())
                {
                    var awaiterType = ((NamedTypeSymbol)getAwaiter.ReturnType).OriginalDefinition.Construct(F.SpecialType(SpecialType.System_Object));
                    awaiterTemp       = F.SynthesizedLocal(awaiterType);
                    getResult         = ((MethodSymbol)getResult.OriginalDefinition).AsMember(awaiterType);
                    isCompletedMethod = ((MethodSymbol)isCompletedMethod.OriginalDefinition).AsMember(awaiterType);
                }
                else
                {
                    awaiterTemp = F.SynthesizedLocal(getAwaiter.ReturnType);
                }

                var awaitIfIncomplete = F.Block(
                    // temp $awaiterTemp = <expr>.GetAwaiter();
                    F.Assignment(
                        F.Local(awaiterTemp),
                        MakeCallMaybeDynamic(expression, getAwaiter, WellKnownMemberNames.GetAwaiter)),

                    // if(!($awaiterTemp.IsCompleted)) { ... }
                    F.If(
                        condition: F.Not(GenerateGetIsCompleted(awaiterTemp, isCompletedMethod)),
                        thenClause: GenerateAwaitForIncompleteTask(awaiterTemp)));

                BoundExpression getResultCall = MakeCallMaybeDynamic(
                    F.Local(awaiterTemp),
                    getResult,
                    WellKnownMemberNames.GetResult,
                    resultsDiscarded: resultPlace == null);

                var nullAwaiter = F.AssignmentExpression(F.Local(awaiterTemp), F.NullOrDefault(awaiterTemp.Type));

                if (resultPlace != null && type.SpecialType != SpecialType.System_Void)
                {
                    // $resultTemp = $awaiterTemp.GetResult();
                    // $awaiterTemp = null;
                    // $resultTemp
                    LocalSymbol resultTemp = F.SynthesizedLocal(type);
                    return(F.Block(
                               ImmutableArray.Create <LocalSymbol>(awaiterTemp, resultTemp),
                               awaitIfIncomplete,
                               F.Assignment(F.Local(resultTemp), getResultCall),
                               F.ExpressionStatement(nullAwaiter),
                               F.Assignment(resultPlace, F.Local(resultTemp))));
                }
                else
                {
                    // $awaiterTemp.GetResult();
                    // $awaiterTemp = null;
                    return(F.Block(
                               ImmutableArray.Create <LocalSymbol>(awaiterTemp),
                               awaitIfIncomplete,
                               F.ExpressionStatement(getResultCall),
                               F.ExpressionStatement(nullAwaiter)));
                }
            }
            private BoundBlock VisitAwaitExpression(BoundAwaitExpression node, BoundExpression resultPlace)
            {
                var expression = (BoundExpression)Visit(node.Expression);
                resultPlace = (BoundExpression)Visit(resultPlace);
                MethodSymbol getAwaiter = VisitMethodSymbol(node.GetAwaiter);
                MethodSymbol getResult = VisitMethodSymbol(node.GetResult);
                MethodSymbol isCompletedMethod = ((object)node.IsCompleted != null) ? VisitMethodSymbol(node.IsCompleted.GetMethod) : null;
                TypeSymbol type = VisitType(node.Type);

                LocalSymbol awaiterTemp;
                if ((object)getResult == null)
                {
                    awaiterTemp = F.SynthesizedLocal(DynamicTypeSymbol.Instance);
                }
                else if (type.IsDynamic())
                {
                    var awaiterType = ((NamedTypeSymbol)getAwaiter.ReturnType).OriginalDefinition.Construct(F.SpecialType(SpecialType.System_Object));
                    awaiterTemp = F.SynthesizedLocal(awaiterType);
                    getResult = ((MethodSymbol)getResult.OriginalDefinition).AsMember(awaiterType);
                    isCompletedMethod = ((MethodSymbol)isCompletedMethod.OriginalDefinition).AsMember(awaiterType);
                }
                else
                {
                    awaiterTemp = F.SynthesizedLocal(getAwaiter.ReturnType);
                }

                var awaitIfIncomplete = F.Block(
                    // temp $awaiterTemp = <expr>.GetAwaiter();
                    F.Assignment(
                        F.Local(awaiterTemp),
                        MakeCallMaybeDynamic(expression, getAwaiter, WellKnownMemberNames.GetAwaiter)),

                    // if(!($awaiterTemp.IsCompleted)) { ... }
                    F.If(
                        condition: F.Not(GenerateGetIsCompleted(awaiterTemp, isCompletedMethod)),
                        thenClause: GenerateAwaitForIncompleteTask(awaiterTemp)));

                BoundExpression getResultCall = MakeCallMaybeDynamic(
                    F.Local(awaiterTemp),
                    getResult,
                    WellKnownMemberNames.GetResult,
                    resultsDiscarded: resultPlace == null);

                var nullAwaiter = F.AssignmentExpression(F.Local(awaiterTemp), F.NullOrDefault(awaiterTemp.Type));
                if (resultPlace != null && type.SpecialType != SpecialType.System_Void)
                {
                    // $resultTemp = $awaiterTemp.GetResult();
                    // $awaiterTemp = null;
                    // $resultTemp
                    LocalSymbol resultTemp = F.SynthesizedLocal(type);
                    return F.Block(
                        ImmutableArray.Create<LocalSymbol>(awaiterTemp, resultTemp),
                        awaitIfIncomplete,
                        F.Assignment(F.Local(resultTemp), getResultCall),
                        F.ExpressionStatement(nullAwaiter),
                        F.Assignment(resultPlace, F.Local(resultTemp)));
                }
                else
                {
                    // $awaiterTemp.GetResult();
                    // $awaiterTemp = null;
                    return F.Block(
                        ImmutableArray.Create<LocalSymbol>(awaiterTemp),
                        awaitIfIncomplete,
                        F.ExpressionStatement(getResultCall),
                        F.ExpressionStatement(nullAwaiter));
                }
            }
 public override BoundNode VisitAwaitExpression(BoundAwaitExpression node)
 {
     // await expressions must, by now, have been moved to the top level.
     throw ExceptionUtilities.Unreachable;
 }
        private BoundBlock VisitAwaitExpression(BoundAwaitExpression node, BoundExpression resultPlace)
        {
            var expression = (BoundExpression)Visit(node.Expression);
            resultPlace = (BoundExpression)Visit(resultPlace);
            MethodSymbol getAwaiter = VisitMethodSymbol(node.GetAwaiter);
            MethodSymbol getResult = VisitMethodSymbol(node.GetResult);
            MethodSymbol isCompletedMethod = ((object)node.IsCompleted != null) ? VisitMethodSymbol(node.IsCompleted.GetMethod) : null;
            TypeSymbol type = VisitType(node.Type);

            // The awaiter temp facilitates EnC method remapping and thus have to be long-lived.
            // It transfers the awaiter objects from the old version of the MoveNext method to the new one.
            Debug.Assert(node.Syntax.IsKind(SyntaxKind.AwaitExpression));
            TypeSymbol awaiterType = node.IsDynamic ? DynamicTypeSymbol.Instance : getAwaiter.ReturnType;
            var awaiterTemp = F.SynthesizedLocal(awaiterType, syntax: node.Syntax, kind: SynthesizedLocalKind.Awaiter);

            var awaitIfIncomplete = F.Block(
                    // temp $awaiterTemp = <expr>.GetAwaiter();
                    F.Assignment(
                        F.Local(awaiterTemp),
                        MakeCallMaybeDynamic(expression, getAwaiter, WellKnownMemberNames.GetAwaiter)),

                    // hidden sequence point facilitates EnC method remapping, see explanation on SynthesizedLocalKind.Awaiter:
                    F.HiddenSequencePoint(),

                    // if(!($awaiterTemp.IsCompleted)) { ... }
                    F.If(
                        condition: F.Not(GenerateGetIsCompleted(awaiterTemp, isCompletedMethod)),
                        thenClause: GenerateAwaitForIncompleteTask(awaiterTemp)));

            BoundExpression getResultCall = MakeCallMaybeDynamic(
                F.Local(awaiterTemp),
                getResult,
                WellKnownMemberNames.GetResult,
                resultsDiscarded: resultPlace == null);

            var nullAwaiter = F.AssignmentExpression(F.Local(awaiterTemp), F.NullOrDefault(awaiterTemp.Type));
            if (resultPlace != null && type.SpecialType != SpecialType.System_Void)
            {
                // $resultTemp = $awaiterTemp.GetResult();
                // $awaiterTemp = null;
                // $resultTemp
                LocalSymbol resultTemp = F.SynthesizedLocal(type);
                return F.Block(
                    ImmutableArray.Create(awaiterTemp, resultTemp),
                    ImmutableArray<LocalFunctionSymbol>.Empty,
                        awaitIfIncomplete,
                        F.Assignment(F.Local(resultTemp), getResultCall),
                        F.ExpressionStatement(nullAwaiter),
                        F.Assignment(resultPlace, F.Local(resultTemp)));
            }
            else
            {
                // $awaiterTemp.GetResult();
                // $awaiterTemp = null;
                return F.Block(
                    ImmutableArray.Create(awaiterTemp),
                    ImmutableArray<LocalFunctionSymbol>.Empty,
                        awaitIfIncomplete,
                        F.ExpressionStatement(getResultCall),
                        F.ExpressionStatement(nullAwaiter));
            }
        }
 public override BoundNode VisitAwaitExpression(BoundAwaitExpression node)
 {
     base.VisitAwaitExpression(node);
     MarkLocalsUnassigned();
     return(null);
 }
Esempio n. 26
0
 public override BoundNode VisitAwaitExpression(BoundAwaitExpression node)
 {
     _sawAwait = true;
     return(null);
 }
Esempio n. 27
0
 public override BoundNode?VisitAwaitExpression(BoundAwaitExpression node)
 {
     ContainsAwait = true;
     return(null);
 }
        private BoundBlock VisitAwaitExpression(BoundAwaitExpression node, BoundExpression resultPlace)
        {
            var expression = (BoundExpression)Visit(node.Expression);
            resultPlace = (BoundExpression)Visit(resultPlace);
            MethodSymbol getAwaiter = VisitMethodSymbol(node.GetAwaiter);
            MethodSymbol getResult = VisitMethodSymbol(node.GetResult);
            MethodSymbol isCompletedMethod = ((object)node.IsCompleted != null) ? VisitMethodSymbol(node.IsCompleted.GetMethod) : null;
            TypeSymbol type = VisitType(node.Type);

            // The lifespan of awaiter temp doesn't cross sequence points (user code in between awaits), so it doesn't need to be named.
            TypeSymbol awaiterType = node.IsDynamic ? DynamicTypeSymbol.Instance : getAwaiter.ReturnType;
            var awaiterTemp = F.SynthesizedLocal(awaiterType);

            var awaitIfIncomplete = F.Block(
                    // temp $awaiterTemp = <expr>.GetAwaiter();
                    F.Assignment(
                        F.Local(awaiterTemp),
                        MakeCallMaybeDynamic(expression, getAwaiter, WellKnownMemberNames.GetAwaiter)),

                    // if(!($awaiterTemp.IsCompleted)) { ... }
                    F.If(
                        condition: F.Not(GenerateGetIsCompleted(awaiterTemp, isCompletedMethod)),
                        thenClause: GenerateAwaitForIncompleteTask(awaiterTemp)));

            BoundExpression getResultCall = MakeCallMaybeDynamic(
                F.Local(awaiterTemp),
                getResult,
                WellKnownMemberNames.GetResult,
                resultsDiscarded: resultPlace == null);

            var nullAwaiter = F.AssignmentExpression(F.Local(awaiterTemp), F.NullOrDefault(awaiterTemp.Type));
            if (resultPlace != null && type.SpecialType != SpecialType.System_Void)
            {
                // $resultTemp = $awaiterTemp.GetResult();
                // $awaiterTemp = null;
                // $resultTemp
                LocalSymbol resultTemp = F.SynthesizedLocal(type);
                return F.Block(
                    ImmutableArray.Create(awaiterTemp, resultTemp),
                        awaitIfIncomplete,
                        F.Assignment(F.Local(resultTemp), getResultCall),
                        F.ExpressionStatement(nullAwaiter),
                        F.Assignment(resultPlace, F.Local(resultTemp)));
            }
            else
            {
                // $awaiterTemp.GetResult();
                // $awaiterTemp = null;
                return F.Block(
                    ImmutableArray.Create(awaiterTemp),
                        awaitIfIncomplete,
                        F.ExpressionStatement(getResultCall),
                        F.ExpressionStatement(nullAwaiter));
            }
        }