Ejemplo n.º 1
0
        public override BoundNode VisitIsOperator(BoundIsOperator node)
        {
            // rewrite is needed only for cases where there are no errors and
            // no warnings (i.e. non-constant result) generated during binding
            if (!node.HasErrors && node.ConstantValue == null)
            {
                BoundExpression operand     = node.Operand;
                var             targetType  = node.TargetType.Type;
                var             operandType = operand.Type;

                Debug.Assert(operandType != null);
                if (operandType.IsNullableType())
                {
                    //TODO: handle nullable types once nullable conversions are implemented
                }
                else if (!operandType.IsValueType)
                {
                    if (operandType.IsSameType(targetType))
                    {
                        // operand with bound identity or implicit conversion
                        // We can replace the "is" instruction with a null check
                        Visit(operand);
                        if (operandType.TypeKind == TypeKind.TypeParameter)
                        {
                            // We need to box the type parameter even if it is a known
                            // reference type to ensure there are no verifier errors
                            operand = new BoundConversion(operand.Syntax, operand.SyntaxTree, operand,
                                                          ConversionKind.Boxing, this.containingSymbol, false, false, null,
                                                          compilation.GetSpecialType(SpecialType.System_Object));
                        }
                        return(new BoundBinaryOperator(node.Syntax, node.SyntaxTree, BinaryOperatorKind.NotEqual,
                                                       operand, new BoundLiteral(null, null, ConstantValue.Null, null), null, node.Type));
                    }
                }
            }
            return(base.VisitIsOperator(node));
        }
Ejemplo n.º 2
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));
        }