Exemple #1
0
        public override BoundNode VisitSpillSequence(BoundSpillSequence node)
        {
            var builder = new BoundSpillSequenceBuilder();

            // Ensure later errors (e.g. in async rewriting) are associated with the correct node.
            _F.Syntax = node.Syntax;

            builder.AddStatements(VisitList(node.SideEffects));
            builder.AddLocals(node.Locals);
            var value = VisitExpression(ref builder, node.Value);

            return(builder.Update(value));
        }
Exemple #2
0
        private BoundExpression Spill(
            BoundSpillSequenceBuilder builder,
            BoundExpression expression,
            RefKind refKind      = RefKind.None,
            bool sideEffectsOnly = false)
        {
            Debug.Assert(builder != null);

            while (true)
            {
                switch (expression.Kind)
                {
                case BoundKind.ArrayInitialization:
                    Debug.Assert(refKind == RefKind.None);
                    Debug.Assert(!sideEffectsOnly);
                    var arrayInitialization = (BoundArrayInitialization)expression;
                    var newInitializers     = VisitExpressionList(ref builder, arrayInitialization.Initializers, forceSpill: true);
                    return(arrayInitialization.Update(newInitializers));

                case BoundKind.ArgListOperator:
                    Debug.Assert(refKind == RefKind.None);
                    Debug.Assert(!sideEffectsOnly);
                    var argumentList = (BoundArgListOperator)expression;
                    var newArgs      = VisitExpressionList(ref builder, argumentList.Arguments, argumentList.ArgumentRefKindsOpt, forceSpill: true);
                    return(argumentList.Update(newArgs, argumentList.ArgumentRefKindsOpt, argumentList.Type));

                case SpillSequenceBuilder:
                    var sequenceBuilder = (BoundSpillSequenceBuilder)expression;
                    builder.Include(sequenceBuilder);
                    expression = sequenceBuilder.Value;
                    continue;

                case BoundKind.Sequence:
                    // We don't need promote short-lived variables defined by the sequence to long-lived,
                    // since neither the side-effects nor the value of the sequence contains await
                    // (otherwise it would be converted to a SpillSequenceBuilder).
                    var sequence = (BoundSequence)expression;
                    builder.AddLocals(sequence.Locals);
                    builder.AddExpressions(sequence.SideEffects);
                    expression = sequence.Value;
                    continue;

                case BoundKind.ThisReference:
                case BoundKind.BaseReference:
                    if (refKind != RefKind.None || expression.Type.IsReferenceType)
                    {
                        return(expression);
                    }

                    goto default;

                case BoundKind.Parameter:
                    if (refKind != RefKind.None)
                    {
                        return(expression);
                    }

                    goto default;

                case BoundKind.Local:
                    var local = (BoundLocal)expression;
                    if (local.LocalSymbol.SynthesizedKind == SynthesizedLocalKind.AwaitSpill || refKind != RefKind.None)
                    {
                        return(local);
                    }

                    goto default;

                case BoundKind.FieldAccess:
                    var field = (BoundFieldAccess)expression;
                    if (field.FieldSymbol.IsReadOnly)
                    {
                        if (field.FieldSymbol.IsStatic)
                        {
                            return(field);
                        }
                        if (field.FieldSymbol.ContainingType.IsValueType)
                        {
                            goto default;
                        }
                        // save the receiver; can get the field later.
                        var receiver = Spill(builder, field.ReceiverOpt, (refKind != RefKind.None && field.FieldSymbol.Type.IsReferenceType) ? refKind : RefKind.None, sideEffectsOnly);
                        return(field.Update(receiver, field.FieldSymbol, field.ConstantValueOpt, field.ResultKind, field.Type));
                    }
                    goto default;

                case BoundKind.Call:
                    var call = (BoundCall)expression;
                    if (refKind != RefKind.None)
                    {
                        Debug.Assert(call.Method.RefKind != RefKind.None);
                        _F.Diagnostics.Add(ErrorCode.ERR_RefReturningCallAndAwait, _F.Syntax.Location, call.Method);
                        refKind = RefKind.None;     // Switch the RefKind to avoid asserting later in the pipeline
                    }
                    goto default;

                case BoundKind.Literal:
                case BoundKind.TypeExpression:
                    return(expression);

                case BoundKind.ConditionalReceiver:
                    // we will rewrite this as a part of rewriting whole LoweredConditionalAccess
                    // later, if needed
                    return(expression);

                default:
                    if (expression.Type.SpecialType == SpecialType.System_Void || sideEffectsOnly)
                    {
                        builder.AddStatement(_F.ExpressionStatement(expression));
                        return(null);
                    }
                    else
                    {
                        BoundAssignmentOperator assignToTemp;
                        Debug.Assert(_F.Syntax.IsKind(SyntaxKind.AwaitExpression));

                        var replacement = _F.StoreToTemp(
                            expression,
                            out assignToTemp,
                            refKind: refKind,
                            kind: SynthesizedLocalKind.AwaitSpill,
                            syntaxOpt: _F.Syntax);

                        builder.AddLocal(replacement.LocalSymbol, _F.Diagnostics);
                        builder.AddStatement(_F.ExpressionStatement(assignToTemp));
                        return(replacement);
                    }
                }
            }
        }