/// <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); }
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))); }
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)); }
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))); }