Exemplo n.º 1
0
        private BoundExpression HoistRefInitialization(SynthesizedLocal local, BoundAssignmentOperator node)
        {
            Debug.Assert(local.SynthesizedKind == SynthesizedLocalKind.Spill);
            Debug.Assert(local.SyntaxOpt != null);
            Debug.Assert(this.OriginalMethod.IsAsync);

            var right = (BoundExpression)Visit(node.Right);

            var sideEffects = ArrayBuilder <BoundExpression> .GetInstance();

            bool needsSacrificialEvaluation = false;
            var  hoistedFields = ArrayBuilder <StateMachineFieldSymbol> .GetInstance();

            SyntaxNode awaitSyntaxOpt;
            int        syntaxOffset;

            if (F.Compilation.Options.OptimizationLevel == OptimizationLevel.Debug)
            {
                awaitSyntaxOpt = local.GetDeclaratorSyntax();
                Debug.Assert(awaitSyntaxOpt.IsKind(SyntaxKind.AwaitExpression) || awaitSyntaxOpt.IsKind(SyntaxKind.SwitchExpression));
                syntaxOffset = OriginalMethod.CalculateLocalSyntaxOffset(LambdaUtilities.GetDeclaratorPosition(awaitSyntaxOpt), awaitSyntaxOpt.SyntaxTree);
            }
            else
            {
                // These are only used to calculate debug id for ref-spilled variables,
                // no need to do so in release build.
                awaitSyntaxOpt = null;
                syntaxOffset   = -1;
            }

            var replacement = HoistExpression(right, awaitSyntaxOpt, syntaxOffset, local.RefKind, sideEffects, hoistedFields, ref needsSacrificialEvaluation);

            proxies.Add(local, new CapturedToExpressionSymbolReplacement(replacement, hoistedFields.ToImmutableAndFree(), isReusable: true));

            if (needsSacrificialEvaluation)
            {
                var type            = TypeMap.SubstituteType(local.Type).Type;
                var sacrificialTemp = F.SynthesizedLocal(type, refKind: RefKind.Ref);
                Debug.Assert(TypeSymbol.Equals(type, replacement.Type, TypeCompareKind.ConsiderEverything2));
                return(F.Sequence(ImmutableArray.Create(sacrificialTemp), sideEffects.ToImmutableAndFree(), F.AssignmentExpression(F.Local(sacrificialTemp), replacement, isRef: true)));
            }

            if (sideEffects.Count == 0)
            {
                sideEffects.Free();
                return(null);
            }

            var last = sideEffects.Last();

            sideEffects.RemoveLast();
            return(F.Sequence(ImmutableArray <LocalSymbol> .Empty, sideEffects.ToImmutableAndFree(), last));
        }