Beispiel #1
0
        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);
        }
Beispiel #2
0
        /// <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));
            }
        }
Beispiel #3
0
 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);
     }
 }
Beispiel #6
0
 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)),
     };
 }
Beispiel #7
0
 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);
 }
Beispiel #8
0
        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());
            }
        }
Beispiel #9
0
        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);
            }
        }
Beispiel #11
0
 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);
     }
 }
Beispiel #12
0
 internal static BoundConstant?ComputeConstant(
     BoundUnaryOperator @operator, BoundExpression operand)
 {
     if (operand.ConstantValue is { })
Beispiel #13
0
        /// <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);
        }
Beispiel #16
0
        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);
        }
Beispiel #17
0
        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));
        }
Beispiel #18
0
 public BoundUnaryExpression(SyntaxNode syntax, BoundUnaryOperator @operator, BoundExpression operand)
     : base(syntax) =>
     (this.Operator, this.Operand, this.ConstantValue) =
Beispiel #19
0
 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);
     }
 }
Beispiel #20
0
        /// <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));
        }