/// <summary>
        /// Rewrite an assignment operator.
        ///
        /// Possible cases:
        ///   (1) Neither the lvalue nor rvalue contain an await expression.
        ///   (2) Only the lvalue contains an await expression.
        ///   (3) The rvalue contains an await expression, and the lvalue is one of:
        ///     (a) an await-containing expression,
        ///     (b) an array access,
        ///     (c) a field access, or
        ///     (d) a local
        ///
        /// </summary>
        public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
        {
            BoundExpression leftNode  = (BoundExpression)this.Visit(node.Left);
            BoundExpression rightNode = (BoundExpression)this.Visit(node.Right);
            TypeSymbol      type      = this.VisitType(node.Type);

            if (!RequiresSpill(leftNode, rightNode))
            {
                // Case (1) - no await expression:
                return(node.Update(leftNode, rightNode, node.RefKind, type));
            }

            if (!RequiresSpill(rightNode))
            {
                // Case (2) - only lvalue contains await
                //     Spill(l_sideEffects, lvalue) = rvalue
                //   is rewritten as:
                //     Spill(l_sideEffects, lvalue = rvalue)

                var spill         = (BoundSpillSequence)leftNode;
                var newAssignment = node.Update(spill.Value, rightNode, node.RefKind, type);
                return(RewriteSpillSequence(spill, newAssignment));
            }

            // Case (3) -
            return(SpillAssignmentOperator(node, leftNode, (BoundSpillSequence)rightNode));
        }
        /// <summary>
        /// Rewrite an assignment operator.
        /// 
        /// Possible cases:
        ///   (1) Neither the lvalue nor rvalue contain an await expression.
        ///   (2) Only the lvalue contains an await expression.
        ///   (3) The rvalue contains an await expression, and the lvalue is one of:
        ///     (a) an await-containing expression,
        ///     (b) an array access,
        ///     (c) a field access, or
        ///     (d) a local
        ///
        /// </summary>
        public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
        {
            BoundExpression leftNode = (BoundExpression)this.Visit(node.Left);
            BoundExpression rightNode = (BoundExpression)this.Visit(node.Right);
            TypeSymbol type = this.VisitType(node.Type);

            if (!RequiresSpill(leftNode, rightNode))
            {
                // Case (1) - no await expression:
                return node.Update(leftNode, rightNode, node.RefKind, type);
            }

            if (!RequiresSpill(rightNode))
            {
                // Case (2) - only lvalue contains await
                //     Spill(l_sideEffects, lvalue) = rvalue
                //   is rewritten as:
                //     Spill(l_sideEffects, lvalue = rvalue)

                var spill = (BoundSpillSequence) leftNode;
                var newAssignment = node.Update(spill.Value, rightNode, node.RefKind, type);
                return RewriteSpillSequence(spill, newAssignment);
            }

            // Case (3) -
            return SpillAssignmentOperator(node, leftNode, (BoundSpillSequence) rightNode);
        }
Exemple #3
0
        public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
        {
            BoundSpillSequenceBuilder builder = null;
            var             right             = VisitExpression(ref builder, node.Right);
            BoundExpression left;

            if (builder == null || node.Left.Kind == BoundKind.Local)
            {
                left = VisitExpression(ref builder, node.Left);
            }
            else
            {
                // if the right-hand-side has await, spill the left
                var leftBuilder = new BoundSpillSequenceBuilder();
                left = VisitExpression(ref leftBuilder, node.Left);
                if (left.Kind != BoundKind.Local)
                {
                    left = Spill(leftBuilder, left, RefKind.Ref);
                }

                leftBuilder.Include(builder);
                builder = leftBuilder;
            }

            return(UpdateExpression(builder, node.Update(left, right, node.RefKind, node.Type)));
        }
Exemple #4
0
        public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
        {
            BoundSpillSequence2 ss = null;
            var             right  = VisitExpression(ref ss, node.Right);
            BoundExpression left;

            if (ss == null || node.Left.Kind == BoundKind.Local)
            {
                left = VisitExpression(ref ss, node.Left);
            }
            else
            {
                // if the right-hand-side has await, spill the left
                var ss2 = new BoundSpillSequence2();
                left = VisitExpression(ref ss2, node.Left);
                if (left.Kind != BoundKind.Local)
                {
                    left = Spill(ss2, left, RefKind.Ref);
                }
                ss2.IncludeSequence(ss);
                ss = ss2;
            }

            return(UpdateExpression(ss, node.Update(left, right, node.RefKind, node.Type)));
        }
 private BoundNode SpillAssignmentOperator(BoundAssignmentOperator node, BoundExpression left, BoundSpillSequence right)
 {
     var spillBuilder = new SpillBuilder();
     var spilledLeftNode = SpillLValue(left, spillBuilder);
     var innerSpill = node.Update(spilledLeftNode, right.Value, node.RefKind, node.Type);
     spillBuilder.AddSpill(right);
     return spillBuilder.BuildSequenceAndFree(F, innerSpill);
 }
        private BoundNode SpillAssignmentOperator(BoundAssignmentOperator node, BoundExpression left, BoundSpillSequence right)
        {
            var spillBuilder    = new SpillBuilder();
            var spilledLeftNode = SpillLValue(left, spillBuilder);
            var innerSpill      = node.Update(spilledLeftNode, right.Value, node.RefKind, node.Type);

            spillBuilder.AddSpill(right);
            return(spillBuilder.BuildSequenceAndFree(F, innerSpill));
        }
        public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
        {
            BoundSpillSequence2 ss = null;
            var right = VisitExpression(ref ss, node.Right);
            BoundExpression left;
            if (ss == null || node.Left.Kind == BoundKind.Local)
            {
                left = VisitExpression(ref ss, node.Left);
            }
            else
            {
                // if the right-hand-side has await, spill the left
                var ss2 = new BoundSpillSequence2();
                left = VisitExpression(ref ss2, node.Left);
                if (left.Kind != BoundKind.Local) left = Spill(ss2, left, RefKind.Ref);
                ss2.IncludeSequence(ss);
                ss = ss2;
            }

            return UpdateExpression(ss, node.Update(left, right, node.RefKind, node.Type));
        }
Exemple #8
0
        public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
        {
            BoundSpillSequenceBuilder builder = null;
            var right = VisitExpression(ref builder, node.Right);

            BoundExpression left = node.Left;

            if (builder == null)
            {
                left = VisitExpression(ref builder, left);
            }
            else
            {
                // if the right-hand-side has await, spill the left
                var leftBuilder = new BoundSpillSequenceBuilder();

                switch (left.Kind)
                {
                case BoundKind.Local:
                case BoundKind.Parameter:
                    // locals and parameters are directly assignable, LHS is not on the stack so nothing to spill
                    break;

                case BoundKind.FieldAccess:
                    var field = (BoundFieldAccess)left;
                    // static fields are directly assignable, LHS is not on the stack, nothing to spill
                    if (field.FieldSymbol.IsStatic)
                    {
                        break;
                    }

                    // instance fields are directly assignable, but receiver is pushed, so need to spill that.
                    var receiver = VisitExpression(ref leftBuilder, field.ReceiverOpt);
                    receiver = Spill(builder, receiver, field.FieldSymbol.ContainingType.IsValueType ? RefKind.Ref : RefKind.None);
                    left     = field.Update(receiver, field.FieldSymbol, field.ConstantValueOpt, field.ResultKind, field.Type);
                    break;

                case BoundKind.ArrayAccess:
                    var arrayAccess = (BoundArrayAccess)left;
                    // array and indices are pushed on stack so need to spill that
                    var expression = VisitExpression(ref leftBuilder, arrayAccess.Expression);
                    expression = Spill(builder, expression, RefKind.None);
                    var indices = this.VisitExpressionList(ref builder, arrayAccess.Indices, forceSpill: true);
                    left = arrayAccess.Update(expression, indices, arrayAccess.Type);
                    break;

                default:
                    // must be something indirectly assignable, just visit and spill as an ordinary Ref  (not a RefReadOnly!!)
                    //
                    // NOTE: in some cases this will result in spiller producing an error.
                    //       For example if the LHS is a ref-returning method like
                    //
                    //       obj.RefReturning(a, b, c) = await Something();
                    //
                    //       the spiller would eventually have to spill the evaluation result of "refReturning" call as an ordinary Ref,
                    //       which it can't.
                    left = Spill(leftBuilder, VisitExpression(ref leftBuilder, left), RefKind.Ref);
                    break;
                }

                leftBuilder.Include(builder);
                builder = leftBuilder;
            }

            return(UpdateExpression(builder, node.Update(left, right, node.IsRef, node.Type)));
        }