private void EmitUnaryCheckedOperatorExpression(BoundUnaryOperator expression, bool used) { Debug.Assert(expression.OperatorKind.Operator() == UnaryOperatorKind.UnaryMinus); var type = expression.OperatorKind.OperandTypes(); // Spec 7.6.2 // Implementation of unary minus has two overloads: // int operator –(int x) // long operator –(long x) // // The result is computed by subtracting x from zero. // If the value of x is the smallest representable value of the operand type (−2^31 for int or −2^63 for long), // then the mathematical negation of x is not representable within the operand type. If this occurs within a checked context, // a System.OverflowException is thrown; if it occurs within an unchecked context, // the result is the value of the operand and the overflow is not reported. Debug.Assert(type == UnaryOperatorKind.Int || type == UnaryOperatorKind.Long); // ldc.i4.0 // conv.i8 (when the operand is 64bit) // <expr> // sub.ovf _builder.EmitOpCode(ILOpCode.Ldc_i4_0); if (type == UnaryOperatorKind.Long) { _builder.EmitOpCode(ILOpCode.Conv_i8); } EmitExpression(expression.Operand, used: true); _builder.EmitOpCode(ILOpCode.Sub_ovf); EmitPopIfUnused(used); }
/// <summary> /// Rewrite bound unary operators representing increments or decrements. Leave other nodes as-is. /// </summary> public override BoundNode VisitUnaryOperator(BoundUnaryOperator node) { Debug.Assert(node != null); if (node.HasErrors) { return(node); } switch (node.OperatorKind.Operator()) { case UnaryOperatorKind.PrefixIncrement: return(LowerOperator(node, isPrefix: true, isIncrement: true)); case UnaryOperatorKind.PrefixDecrement: return(LowerOperator(node, isPrefix: true, isIncrement: false)); case UnaryOperatorKind.PostfixIncrement: return(LowerOperator(node, isPrefix: false, isIncrement: true)); case UnaryOperatorKind.PostfixDecrement: return(LowerOperator(node, isPrefix: false, isIncrement: false)); default: return(base.VisitUnaryOperator(node)); } }
internal void Parse(BoundUnaryOperator boundUnaryOperator) { base.Parse(boundUnaryOperator); this.OperatorKind = boundUnaryOperator.OperatorKind; this.Operand = Deserialize(boundUnaryOperator.Operand) as Expression; Debug.Assert(this.Operand != null); }
public override BoundNode VisitUnaryOperator(BoundUnaryOperator node) => node.Update( node.OperatorKind, (BoundExpression)Visit(node.Operand), node.ConstantValueOpt, VisitMethodSymbol(node.MethodOpt), VisitType(node.ConstrainedToTypeOpt), node.ResultKind, VisitType(node.Type));
public BoundUnaryExpression(BoundUnaryOperator op, BoundExpression expression, TypeSymbol resultType, bool isValid) : base(isValid) { ResultType = resultType; Op = op; Expression = expression; if (isValid) { Constant = ConstantFolder.FoldUnary(op, expression); } }
public SwitchVsIfEnum() { _testVarialbe = new VariableSymbol("a", typeof(int)); _expressions = new List <BoundExpression>() { new BoundLiteralExpression(true), new BoundVariableExpression(_testVarialbe), new BoundAssignmentExpression(new VariableSymbol("b", typeof(int)), new BoundLiteralExpression(1)), new BoundBinaryExpression(new BoundLiteralExpression(1), BoundBinaryOperator.Bind(SyntaxKind.PlusToken, typeof(int), typeof(int)), new BoundLiteralExpression(2)), new BoundUnaryExpression(BoundUnaryOperator.Bind(SyntaxKind.PlusToken, typeof(int)), new BoundLiteralExpression(1)), }; }
public override object VisitUnaryOperator(BoundUnaryOperator node, object arg) { if (node.OperatorKind == UnaryOperatorKind.BoolLogicalNegation) { // We have a special case for the ! unary operator, which can operate in a boolean context (5.3.3.26) VisitCondition(node.Operand); // it inverts the sense of assignedWhenTrue and assignedWhenFalse. this.state = new FlowAnalysisLocalState(this.state.Reachable, this.state.AssignedWhenFalse, this.state.AssignedWhenTrue); } else { VisitExpression(node.Operand); } return(null); }
private void EmitUnaryOperatorExpression(BoundUnaryOperator expression, bool used) { var operatorKind = expression.OperatorKind; if (operatorKind.IsChecked()) { EmitUnaryCheckedOperatorExpression(expression, used); return; } if (!used) { EmitExpression(expression.Operand, used: false); return; } if (operatorKind == UnaryOperatorKind.BoolLogicalNegation) { EmitCondExpr(expression.Operand, sense: false); return; } EmitExpression(expression.Operand, used: true); switch (operatorKind.Operator()) { case UnaryOperatorKind.UnaryMinus: _builder.EmitOpCode(ILOpCode.Neg); break; case UnaryOperatorKind.BitwiseComplement: _builder.EmitOpCode(ILOpCode.Not); break; case UnaryOperatorKind.UnaryPlus: break; default: throw ExceptionUtilities.UnexpectedValue(operatorKind.Operator()); } }
private void EmitUnaryOperatorExpression(BoundUnaryOperator expression, bool used) { var operatorKind = expression.OperatorKind; if (operatorKind.IsChecked()) { EmitUnaryCheckedOperatorExpression(expression, used); return; } if (!used) { EmitExpression(expression.Operand, used: false); return; } if (operatorKind == UnaryOperatorKind.BoolLogicalNegation) { EmitCondExpr(expression.Operand, sense: false); return; } EmitExpression(expression.Operand, used: true); switch (operatorKind.Operator()) { case UnaryOperatorKind.UnaryMinus: _builder.EmitOpCode(ILOpCode.Neg); break; case UnaryOperatorKind.BitwiseComplement: _builder.EmitOpCode(ILOpCode.Not); break; case UnaryOperatorKind.UnaryPlus: break; default: throw ExceptionUtilities.UnexpectedValue(operatorKind.Operator()); } }
/// <summary> /// Rewrite bound unary operators representing increments or decrements. Leave other nodes as-is. /// </summary> public override BoundNode VisitUnaryOperator(BoundUnaryOperator node) { Debug.Assert(node != null); if (node.HasErrors) { return node; } switch (node.OperatorKind.Operator()) { case UnaryOperatorKind.PrefixIncrement: return LowerOperator(node, isPrefix: true, isIncrement: true); case UnaryOperatorKind.PrefixDecrement: return LowerOperator(node, isPrefix: true, isIncrement: false); case UnaryOperatorKind.PostfixIncrement: return LowerOperator(node, isPrefix: false, isIncrement: true); case UnaryOperatorKind.PostfixDecrement: return LowerOperator(node, isPrefix: false, isIncrement: false); default: return base.VisitUnaryOperator(node); } }
public override BoundNode VisitUnaryOperator(BoundUnaryOperator node) { // checked(-x) is emitted as "0 - x" if (node.OperatorKind.IsChecked() && node.OperatorKind.Operator() == UnaryOperatorKind.UnaryMinus) { var origStack = _evalStack; _evalStack++; CannotReusePreviousExpression(); // Loaded 0 on the stack. BoundExpression operand = (BoundExpression)this.Visit(node.Operand); _evalStack = origStack; return node.Update(node.OperatorKind, operand, node.ConstantValueOpt, node.MethodOpt, node.ResultKind, node.Type); } else { return base.VisitUnaryOperator(node); } }
internal static BoundConstant?ComputeConstant( BoundUnaryOperator @operator, BoundExpression operand) { if (operand.ConstantValue is { })
/// <summary> /// By examining the node and the UnaryOperatorKind detemine which builtin operator should be used /// and create an appropriately-typed constant 1. /// </summary> /// <param name="unaryOperatorKindType">The operand type of the built-in increment/decrement operator.</param> /// <param name="node">The unary operation - used to extract an underlying enum type, if necessary.</param> /// <param name="constantOne">Will contain a constant of the type expected by the built-in operator corresponding to binaryOperatorKindType.</param> /// <param name="binaryOperatorKindType">The built-in binary operator that will be used to implement the built-in increment/decrement operator. May have wider types.</param> private static void MakeConstantAndOperatorKind(UnaryOperatorKind unaryOperatorKindType, BoundUnaryOperator node, out ConstantValue constantOne, out BinaryOperatorKind binaryOperatorKindType) { switch (unaryOperatorKindType) { case UnaryOperatorKind.SByte: case UnaryOperatorKind.Short: case UnaryOperatorKind.Int: constantOne = ConstantValue.ConstantValueOne.Int32; binaryOperatorKindType = BinaryOperatorKind.Int; break; case UnaryOperatorKind.Byte: case UnaryOperatorKind.UShort: case UnaryOperatorKind.UInt: case UnaryOperatorKind.Char: constantOne = ConstantValue.ConstantValueOne.UInt32; binaryOperatorKindType = BinaryOperatorKind.UInt; break; case UnaryOperatorKind.Long: constantOne = ConstantValue.ConstantValueOne.Int64; binaryOperatorKindType = BinaryOperatorKind.Long; break; case UnaryOperatorKind.ULong: constantOne = ConstantValue.ConstantValueOne.UInt64; binaryOperatorKindType = BinaryOperatorKind.ULong; break; case UnaryOperatorKind.Float: constantOne = ConstantValue.ConstantValueOne.Single; binaryOperatorKindType = BinaryOperatorKind.Float; break; case UnaryOperatorKind.Double: constantOne = ConstantValue.ConstantValueOne.Double; binaryOperatorKindType = BinaryOperatorKind.Double; break; case UnaryOperatorKind.Decimal: //Dev10 special cased this, but we'll let DecimalRewriter handle it constantOne = ConstantValue.ConstantValueOne.Decimal; binaryOperatorKindType = BinaryOperatorKind.Decimal; break; case UnaryOperatorKind.Enum: SpecialType underlyingSpecialType = node.Type.GetEnumUnderlyingType().SpecialType; switch (underlyingSpecialType) { case SpecialType.System_Int32: MakeConstantAndOperatorKind(UnaryOperatorKind.Int, node, out constantOne, out binaryOperatorKindType); return; case SpecialType.System_UInt32: MakeConstantAndOperatorKind(UnaryOperatorKind.UInt, node, out constantOne, out binaryOperatorKindType); return; case SpecialType.System_Int64: MakeConstantAndOperatorKind(UnaryOperatorKind.Long, node, out constantOne, out binaryOperatorKindType); return; case SpecialType.System_UInt64: MakeConstantAndOperatorKind(UnaryOperatorKind.ULong, node, out constantOne, out binaryOperatorKindType); return; case SpecialType.System_SByte: MakeConstantAndOperatorKind(UnaryOperatorKind.SByte, node, out constantOne, out binaryOperatorKindType); return; case SpecialType.System_Byte: MakeConstantAndOperatorKind(UnaryOperatorKind.Byte, node, out constantOne, out binaryOperatorKindType); return; case SpecialType.System_Int16: MakeConstantAndOperatorKind(UnaryOperatorKind.Short, node, out constantOne, out binaryOperatorKindType); return; case SpecialType.System_UInt16: MakeConstantAndOperatorKind(UnaryOperatorKind.UShort, node, out constantOne, out binaryOperatorKindType); return; default: throw new InvalidOperationException("Unexpected enum underlying type: " + underlyingSpecialType); } case UnaryOperatorKind.Pointer: //UNDONE: pointer operations throw new NotImplementedException(); case UnaryOperatorKind.UserDefined: //UNDONE: overloaded increment/decrement operators throw new NotImplementedException(); case UnaryOperatorKind.Bool: Debug.Assert(false); //Operator does not exist goto default; default: throw new InvalidOperationException("Unexpected operator type: " + unaryOperatorKindType); } }
/// <summary> /// By examining the node and the UnaryOperatorKind detemine which builtin operator should be used /// and create an appropriately-typed constant 1. /// </summary> /// <param name="unaryOperatorKindType">The operand type of the built-in increment/decrement operator.</param> /// <param name="node">The unary operation - used to extract an underlying enum type, if necessary.</param> /// <param name="constantOne">Will contain a constant of the type expected by the built-in operator corresponding to binaryOperatorKindType.</param> /// <param name="binaryOperatorKindType">The built-in binary operator that will be used to implement the built-in increment/decrement operator. May have wider types.</param> private static void MakeConstantAndOperatorKind(UnaryOperatorKind unaryOperatorKindType, BoundUnaryOperator node, out ConstantValue constantOne, out BinaryOperatorKind binaryOperatorKindType) { switch (unaryOperatorKindType) { case UnaryOperatorKind.SByte: case UnaryOperatorKind.Short: case UnaryOperatorKind.Int: constantOne = ConstantValue.ConstantValueOne.Int32; binaryOperatorKindType = BinaryOperatorKind.Int; break; case UnaryOperatorKind.Byte: case UnaryOperatorKind.UShort: case UnaryOperatorKind.UInt: case UnaryOperatorKind.Char: constantOne = ConstantValue.ConstantValueOne.UInt32; binaryOperatorKindType = BinaryOperatorKind.UInt; break; case UnaryOperatorKind.Long: constantOne = ConstantValue.ConstantValueOne.Int64; binaryOperatorKindType = BinaryOperatorKind.Long; break; case UnaryOperatorKind.ULong: constantOne = ConstantValue.ConstantValueOne.UInt64; binaryOperatorKindType = BinaryOperatorKind.ULong; break; case UnaryOperatorKind.Float: constantOne = ConstantValue.ConstantValueOne.Single; binaryOperatorKindType = BinaryOperatorKind.Float; break; case UnaryOperatorKind.Double: constantOne = ConstantValue.ConstantValueOne.Double; binaryOperatorKindType = BinaryOperatorKind.Double; break; case UnaryOperatorKind.Decimal: //Dev10 special cased this, but we'll let DecimalRewriter handle it constantOne = ConstantValue.ConstantValueOne.Decimal; binaryOperatorKindType = BinaryOperatorKind.Decimal; break; case UnaryOperatorKind.Enum: SpecialType underlyingSpecialType = node.Type.GetEnumUnderlyingType().SpecialType; switch (underlyingSpecialType) { case SpecialType.System_Int32: MakeConstantAndOperatorKind(UnaryOperatorKind.Int, node, out constantOne, out binaryOperatorKindType); return; case SpecialType.System_UInt32: MakeConstantAndOperatorKind(UnaryOperatorKind.UInt, node, out constantOne, out binaryOperatorKindType); return; case SpecialType.System_Int64: MakeConstantAndOperatorKind(UnaryOperatorKind.Long, node, out constantOne, out binaryOperatorKindType); return; case SpecialType.System_UInt64: MakeConstantAndOperatorKind(UnaryOperatorKind.ULong, node, out constantOne, out binaryOperatorKindType); return; case SpecialType.System_SByte: MakeConstantAndOperatorKind(UnaryOperatorKind.SByte, node, out constantOne, out binaryOperatorKindType); return; case SpecialType.System_Byte: MakeConstantAndOperatorKind(UnaryOperatorKind.Byte, node, out constantOne, out binaryOperatorKindType); return; case SpecialType.System_Int16: MakeConstantAndOperatorKind(UnaryOperatorKind.Short, node, out constantOne, out binaryOperatorKindType); return; case SpecialType.System_UInt16: MakeConstantAndOperatorKind(UnaryOperatorKind.UShort, node, out constantOne, out binaryOperatorKindType); return; default: throw new InvalidOperationException("Unexpected enum underlying type: " + underlyingSpecialType); } case UnaryOperatorKind.Pointer: //UNDONE: pointer operations throw new NotImplementedException(); case UnaryOperatorKind.UserDefined: //UNDONE: overloaded increment/decrement operators throw new NotImplementedException(); case UnaryOperatorKind.Bool: Debug.Assert(false); //Operator does not exist goto default; default: throw new InvalidOperationException("Unexpected operator type: " + unaryOperatorKindType); } }
/// <summary> /// The rewrites are as follows: /// /// x++ /// temp = x /// x = temp + 1 /// return temp /// x-- /// temp = x /// x = temp - 1 /// return temp /// ++x /// temp = x + 1 /// x = temp /// return temp /// --x /// temp = x - 1 /// x = temp /// return temp /// /// In each case, the literal 1 is of the type required by the builtin addition/subtraction operator that /// will be used. The temp is of the same type as x, but the sum/difference may be wider, in which case a /// conversion is required. /// </summary> /// <param name="node">The unary operator expression representing the increment/decrement.</param> /// <param name="isPrefix">True for prefix, false for postfix.</param> /// <param name="isIncrement">True for increment, false for decrement.</param> /// <returns>A bound sequence that uses a temp to acheive the correct side effects and return value.</returns> private BoundNode LowerOperator(BoundUnaryOperator node, bool isPrefix, bool isIncrement) { BoundExpression operand = node.Operand; TypeSymbol operandType = operand.Type; //type of the variable being incremented Debug.Assert(operandType == node.Type); ConstantValue constantOne; BinaryOperatorKind binaryOperatorKind; MakeConstantAndOperatorKind(node.OperatorKind.OperandTypes(), node, out constantOne, out binaryOperatorKind); binaryOperatorKind |= isIncrement ? BinaryOperatorKind.Addition : BinaryOperatorKind.Subtraction; Debug.Assert(constantOne != null); Debug.Assert(constantOne.SpecialType != SpecialType.None); Debug.Assert(binaryOperatorKind.OperandTypes() != 0); TypeSymbol constantType = compilation.GetSpecialType(constantOne.SpecialType); BoundExpression boundOne = new BoundLiteral( syntax: null, syntaxTree: null, constantValueOpt: constantOne, type: constantType); LocalSymbol tempSymbol = new TempLocalSymbol(operandType, RefKind.None, containingSymbol); BoundExpression boundTemp = new BoundLocal( syntax: null, syntaxTree: null, localSymbol: tempSymbol, constantValueOpt: null, type: operandType); // NOTE: the LHS may have a narrower type than the operator expects, but that // doesn't seem to cause any problems. If a problem does arise, just add an // explicit BoundConversion. BoundExpression newValue = new BoundBinaryOperator( syntax: null, syntaxTree: null, operatorKind: binaryOperatorKind, left: isPrefix ? operand : boundTemp, right: boundOne, constantValueOpt: null, type: constantType); if (constantType != operandType) { newValue = new BoundConversion( syntax: null, syntaxTree: null, operand: newValue, conversionKind: operandType.IsEnumType() ? ConversionKind.ImplicitEnumeration : ConversionKind.ImplicitNumeric, symbolOpt: null, @checked: false, explicitCastInCode: false, constantValueOpt: null, type: operandType); } ReadOnlyArray<BoundExpression> assignments = ReadOnlyArray<BoundExpression>.CreateFrom( new BoundAssignmentOperator( syntax: null, syntaxTree: null, left: boundTemp, right: isPrefix ? newValue : operand, type: operandType), new BoundAssignmentOperator( syntax: null, syntaxTree: null, left: operand, right: isPrefix ? boundTemp : newValue, type: operandType)); return new BoundSequence( syntax: node.Syntax, syntaxTree: node.SyntaxTree, locals: ReadOnlyArray<LocalSymbol>.CreateFrom(tempSymbol), sideEffects: assignments, value: boundTemp, type: operandType); }
private void EmitUnaryCheckedOperatorExpression(BoundUnaryOperator expression, bool used) { Debug.Assert(expression.OperatorKind.Operator() == UnaryOperatorKind.UnaryMinus); var type = expression.OperatorKind.OperandTypes(); // Spec 7.6.2 // Implementation of unary minus has two overloads: // int operator –(int x) // long operator –(long x) // // The result is computed by subtracting x from zero. // If the value of x is the smallest representable value of the operand type (−2^31 for int or −2^63 for long), // then the mathematical negation of x is not representable within the operand type. If this occurs within a checked context, // a System.OverflowException is thrown; if it occurs within an unchecked context, // the result is the value of the operand and the overflow is not reported. Debug.Assert(type == UnaryOperatorKind.Int || type == UnaryOperatorKind.Long); // ldc.i4.0 // conv.i8 (when the operand is 64bit) // <expr> // sub.ovf _builder.EmitOpCode(ILOpCode.Ldc_i4_0); if (type == UnaryOperatorKind.Long) { _builder.EmitOpCode(ILOpCode.Conv_i8); } EmitExpression(expression.Operand, used: true); _builder.EmitOpCode(ILOpCode.Sub_ovf); EmitPopIfUnused(used); }
public static BoundConstant?FoldUnary(BoundUnaryOperator op, BoundExpression operand) { if (operand.Constant is null) { return(null); } var value = operand.Constant.Value; object?res; switch (op) { case BoundUnaryOperator.Identety: res = value; break; case BoundUnaryOperator.Negation: if (value is int i1) { res = -i1; } else if (value is double d1) { res = -d1; } else { throw new Exception("Invalid state"); } break; case BoundUnaryOperator.LogicalNot: if (value is bool b1) { res = !b1; } else { throw new Exception("Invalid state"); } break; case BoundUnaryOperator.BitwiseNot: if (value is int i2) { res = ~i2; } else { throw new Exception("Invalid state"); } break; case BoundUnaryOperator.Invalid: return(null); default: throw new Exception($"Unexpected Unary operator ${op}"); } return(new BoundConstant(res)); }
public BoundUnaryExpression(SyntaxNode syntax, BoundUnaryOperator @operator, BoundExpression operand) : base(syntax) => (this.Operator, this.Operand, this.ConstantValue) =
public override BoundNode VisitUnaryOperator(BoundUnaryOperator node) { // checked(-x) is emitted as "0 - x" if (node.OperatorKind.IsChecked() && node.OperatorKind.Operator() == UnaryOperatorKind.UnaryMinus) { var origStack = StackDepth(); PushEvalStack(new BoundDefaultOperator(node.Syntax, node.Operand.Type), ExprContext.Value); BoundExpression operand = (BoundExpression)this.Visit(node.Operand); return node.Update(node.OperatorKind, operand, node.ConstantValueOpt, node.MethodOpt, node.ResultKind, node.Type); } else { return base.VisitUnaryOperator(node); } }
/// <summary> /// The rewrites are as follows: /// /// x++ /// temp = x /// x = temp + 1 /// return temp /// x-- /// temp = x /// x = temp - 1 /// return temp /// ++x /// temp = x + 1 /// x = temp /// return temp /// --x /// temp = x - 1 /// x = temp /// return temp /// /// In each case, the literal 1 is of the type required by the builtin addition/subtraction operator that /// will be used. The temp is of the same type as x, but the sum/difference may be wider, in which case a /// conversion is required. /// </summary> /// <param name="node">The unary operator expression representing the increment/decrement.</param> /// <param name="isPrefix">True for prefix, false for postfix.</param> /// <param name="isIncrement">True for increment, false for decrement.</param> /// <returns>A bound sequence that uses a temp to acheive the correct side effects and return value.</returns> private BoundNode LowerOperator(BoundUnaryOperator node, bool isPrefix, bool isIncrement) { BoundExpression operand = node.Operand; TypeSymbol operandType = operand.Type; //type of the variable being incremented Debug.Assert(operandType == node.Type); ConstantValue constantOne; BinaryOperatorKind binaryOperatorKind; MakeConstantAndOperatorKind(node.OperatorKind.OperandTypes(), node, out constantOne, out binaryOperatorKind); binaryOperatorKind |= isIncrement ? BinaryOperatorKind.Addition : BinaryOperatorKind.Subtraction; Debug.Assert(constantOne != null); Debug.Assert(constantOne.SpecialType != SpecialType.None); Debug.Assert(binaryOperatorKind.OperandTypes() != 0); TypeSymbol constantType = compilation.GetSpecialType(constantOne.SpecialType); BoundExpression boundOne = new BoundLiteral( syntax: null, syntaxTree: null, constantValueOpt: constantOne, type: constantType); LocalSymbol tempSymbol = new TempLocalSymbol(operandType, RefKind.None, containingSymbol); BoundExpression boundTemp = new BoundLocal( syntax: null, syntaxTree: null, localSymbol: tempSymbol, constantValueOpt: null, type: operandType); // NOTE: the LHS may have a narrower type than the operator expects, but that // doesn't seem to cause any problems. If a problem does arise, just add an // explicit BoundConversion. BoundExpression newValue = new BoundBinaryOperator( syntax: null, syntaxTree: null, operatorKind: binaryOperatorKind, left: isPrefix ? operand : boundTemp, right: boundOne, constantValueOpt: null, type: constantType); if (constantType != operandType) { newValue = new BoundConversion( syntax: null, syntaxTree: null, operand: newValue, conversionKind: operandType.IsEnumType() ? ConversionKind.ImplicitEnumeration : ConversionKind.ImplicitNumeric, symbolOpt: null, @checked: false, explicitCastInCode: false, constantValueOpt: null, type: operandType); } ReadOnlyArray <BoundExpression> assignments = ReadOnlyArray <BoundExpression> .CreateFrom( new BoundAssignmentOperator( syntax : null, syntaxTree : null, left : boundTemp, right : isPrefix ? newValue : operand, type : operandType), new BoundAssignmentOperator( syntax : null, syntaxTree : null, left : operand, right : isPrefix ? boundTemp : newValue, type : operandType)); return(new BoundSequence( syntax: node.Syntax, syntaxTree: node.SyntaxTree, locals: ReadOnlyArray <LocalSymbol> .CreateFrom(tempSymbol), sideEffects: assignments, value: boundTemp, type: operandType)); }