Beispiel #1
0
 private void CheckDynamic(BoundUnaryOperator node)
 {
     if (_inExpressionLambda && node.OperatorKind.IsDynamic())
     {
         Error(ErrorCode.ERR_ExpressionTreeContainsDynamicOperation, node);
     }
 }
        /// <summary>
        /// This rewriter lowers pre-/post- increment/decrement operations (initially represented as
        /// unary operators). We use BoundSequenceExpressions because we need to capture the RHS of the
        /// assignment in a temp variable.
        /// </summary>
        /// <remarks>
        /// This rewriter assumes that it will be run before decimal rewriting (so that it does not have
        /// to lower decimal constants and operations) and call rewriting (so that it does not have to
        /// lower property accesses).
        /// </remarks>
        public override BoundNode VisitUnaryOperator(BoundUnaryOperator node)
        {
            switch (node.OperatorKind.Operator())
            {
                case UnaryOperatorKind.PrefixDecrement:
                case UnaryOperatorKind.PrefixIncrement:
                case UnaryOperatorKind.PostfixDecrement:
                case UnaryOperatorKind.PostfixIncrement:
                    Debug.Assert(false); // these should have been represented as a BoundIncrementOperator
                    return base.VisitUnaryOperator(node);
            }

            // TODO(tomat): We need to pass a parent operator kind into binary operator visitor.
            // We circumvent logic in VisitExpression. The extra logic doesn't apply under these conditions so we are ok. 
            // This is a bit fragile however. Consider refactoring VisitExpression.

            if (node.Operand.Kind == BoundKind.BinaryOperator)
            {
                // Optimization:
                // Binary operator lowering combines the binary operator with IsTrue/IsFalse more efficiently than we can do here.

                var binaryOperator = (BoundBinaryOperator)node.Operand;
                if (node.OperatorKind == UnaryOperatorKind.DynamicTrue && binaryOperator.OperatorKind == BinaryOperatorKind.DynamicLogicalOr ||
                    node.OperatorKind == UnaryOperatorKind.DynamicFalse && binaryOperator.OperatorKind == BinaryOperatorKind.DynamicLogicalAnd)
                {
                    return VisitBinaryOperator(binaryOperator, applyParentUnaryOperator: node);
                }
            }

            BoundExpression loweredOperand = VisitExpression(node.Operand);
            return MakeUnaryOperator(node, node.OperatorKind, node.Syntax, node.MethodOpt, loweredOperand, node.Type);
        }
        public override BoundNode VisitUnaryOperator(BoundUnaryOperator node)
        {
            BoundSpillSequenceBuilder builder = null;
            BoundExpression           operand = VisitExpression(ref builder, node.Operand);

            return(UpdateExpression(builder, node.Update(node.OperatorKind, operand, node.ConstantValueOpt, node.MethodOpt, node.ResultKind, node.Type)));
        }
 public override BoundNode VisitUnaryOperator(BoundUnaryOperator node)
 {
     CheckUnsafeType(node);
     CheckLiftedUnaryOp(node);
     CheckDynamic(node);
     return(base.VisitUnaryOperator(node));
 }
        /// <summary>
        /// This rewriter lowers pre-/post- increment/decrement operations (initially represented as
        /// unary operators). We use BoundSequenceExpressions because we need to capture the RHS of the
        /// assignment in a temp variable.
        /// </summary>
        /// <remarks>
        /// This rewriter assumes that it will be run before decimal rewriting (so that it does not have
        /// to lower decimal constants and operations) and call rewriting (so that it does not have to
        /// lower property accesses).
        /// </remarks>
        public override BoundNode VisitUnaryOperator(BoundUnaryOperator node)
        {
            switch (node.OperatorKind.Operator())
            {
            case UnaryOperatorKind.PrefixDecrement:
            case UnaryOperatorKind.PrefixIncrement:
            case UnaryOperatorKind.PostfixDecrement:
            case UnaryOperatorKind.PostfixIncrement:
                Debug.Assert(false);     // these should have been represented as a BoundIncrementOperator
                return(base.VisitUnaryOperator(node));
            }

            // TODO(tomat): We need to pass a parent operator kind into binary operator visitor.
            // We circumvent logic in VisitExpression. The extra logic doesn't apply under these conditions so we are ok.
            // This is a bit fragile however. Consider refactoring VisitExpression.

            if (node.Operand.Kind == BoundKind.BinaryOperator)
            {
                // Optimization:
                // Binary operator lowering combines the binary operator with IsTrue/IsFalse more efficiently than we can do here.

                var binaryOperator = (BoundBinaryOperator)node.Operand;
                if (node.OperatorKind == UnaryOperatorKind.DynamicTrue && binaryOperator.OperatorKind == BinaryOperatorKind.DynamicLogicalOr ||
                    node.OperatorKind == UnaryOperatorKind.DynamicFalse && binaryOperator.OperatorKind == BinaryOperatorKind.DynamicLogicalAnd)
                {
                    return(VisitBinaryOperator(binaryOperator, applyParentUnaryOperator: node));
                }
            }

            BoundExpression loweredOperand = VisitExpression(node.Operand);

            return(MakeUnaryOperator(node, node.OperatorKind, node.Syntax, node.MethodOpt, loweredOperand, node.Type));
        }
        public BoundExpression VisitBinaryOperator(BoundBinaryOperator node, BoundUnaryOperator applyParentUnaryOperator = null)
        {
            // In machine-generated code we frequently end up with binary operator trees that are deep on the left,
            // such as a + b + c + d ...
            // To avoid blowing the call stack, we make an explicit stack of the binary operators to the left, 
            // and then lower by traversing the explicit stack.

            var stack = ArrayBuilder<BoundBinaryOperator>.GetInstance();

            for (BoundBinaryOperator current = node; current != null; current = current.Left as BoundBinaryOperator)
            {
                stack.Push(current);
            }

            BoundExpression loweredLeft = VisitExpression(stack.Peek().Left);
            while (stack.Count > 0)
            {
                BoundBinaryOperator original = stack.Pop();
                BoundExpression loweredRight = VisitExpression(original.Right);
                loweredLeft = MakeBinaryOperator(original, original.Syntax, original.OperatorKind, loweredLeft, loweredRight, original.Type, original.MethodOpt,
                    applyParentUnaryOperator: (stack.Count == 0) ? applyParentUnaryOperator : null);
            }

            stack.Free();
            return loweredLeft;
        }
 private BoundExpression MakeBinaryOperator(
     CSharpSyntaxNode syntax,
     BinaryOperatorKind operatorKind,
     BoundExpression loweredLeft,
     BoundExpression loweredRight,
     TypeSymbol type,
     MethodSymbol method,
     bool isPointerElementAccess = false,
     bool isCompoundAssignment = false,
     BoundUnaryOperator applyParentUnaryOperator = null)
 {
     return MakeBinaryOperator(null, syntax, operatorKind, loweredLeft, loweredRight, type, method, isPointerElementAccess, isCompoundAssignment, applyParentUnaryOperator);
 }
Beispiel #8
0
        private void CheckLiftedUnaryOp(BoundUnaryOperator node)
        {
            Debug.Assert(node != null);

            if (!node.OperatorKind.IsLifted())
            {
                return;
            }

            // CS0458: The result of the expression is always 'null' of type '{0}'
            if (node.Operand.NullableNeverHasValue())
            {
                Error(ErrorCode.WRN_AlwaysNull, node, node.Type);
            }
        }
        private BoundExpression VisitUnaryOperator(BoundUnaryOperator node)
        {
            var arg        = node.Operand;
            var loweredArg = Visit(arg);
            var opKind     = node.OperatorKind;
            var op         = opKind & UnaryOperatorKind.OpMask;
            var isChecked  = (opKind & UnaryOperatorKind.Checked) != 0;

            string opname;

            switch (op)
            {
            case UnaryOperatorKind.UnaryPlus:
                if ((object)node.MethodOpt == null)
                {
                    return(loweredArg);
                }
                opname = "UnaryPlus";
                break;

            case UnaryOperatorKind.UnaryMinus:
                opname = isChecked ? "NegateChecked" : "Negate";
                break;

            case UnaryOperatorKind.BitwiseComplement:
            case UnaryOperatorKind.LogicalNegation:
                opname = "Not";
                break;

            default:
                throw ExceptionUtilities.UnexpectedValue(op);
            }

            if (node.OperatorKind.OperandTypes() == UnaryOperatorKind.Enum && (opKind & UnaryOperatorKind.Lifted) != 0)
            {
                Debug.Assert((object)node.MethodOpt == null);
                var promotedType = PromotedType(arg.Type.StrippedType().GetEnumUnderlyingType());
                promotedType = _nullableType.Construct(promotedType);
                loweredArg   = Convert(loweredArg, arg.Type, promotedType, isChecked, false);
                var result = ExprFactory(opname, loweredArg);
                return(Demote(result, node.Type, isChecked));
            }

            return(((object)node.MethodOpt == null)
                ? ExprFactory(opname, loweredArg)
                : ExprFactory(opname, loweredArg, _bound.MethodInfo(node.MethodOpt)));
        }
        public override BoundNode VisitUnaryOperator(BoundUnaryOperator node)
        {
            BoundExpression operand = (BoundExpression)this.Visit(node.Operand);
            TypeSymbol type = this.VisitType(node.Type);

            if (operand.Kind != BoundKind.SpillSequence)
            {
                return node.Update(node.OperatorKind, operand, node.ConstantValueOpt, node.MethodOpt, node.ResultKind, type);
            }

            var spill = (BoundSpillSequence)operand;
            return RewriteSpillSequence(spill,
                node.Update(
                    node.OperatorKind,
                    spill.Value,
                    node.ConstantValueOpt,
                    node.MethodOpt,
                    node.ResultKind,
                    type));
        }
        public override BoundNode VisitUnaryOperator(BoundUnaryOperator node)
        {
            BoundExpression operand = (BoundExpression)this.Visit(node.Operand);
            TypeSymbol      type    = this.VisitType(node.Type);

            if (operand.Kind != BoundKind.SpillSequence)
            {
                return(node.Update(node.OperatorKind, operand, node.ConstantValueOpt, node.MethodOpt, node.ResultKind, type));
            }

            var spill = (BoundSpillSequence)operand;

            return(RewriteSpillSequence(spill,
                                        node.Update(
                                            node.OperatorKind,
                                            spill.Value,
                                            node.ConstantValueOpt,
                                            node.MethodOpt,
                                            node.ResultKind,
                                            type)));
        }
Beispiel #12
0
 public override BoundNode VisitUnaryOperator(BoundUnaryOperator node)
 {
     BoundSpillSequence2 ss = null;
     BoundExpression operand = VisitExpression(ref ss, node.Operand);
     return UpdateExpression(ss, node.Update(node.OperatorKind, operand, node.ConstantValueOpt, node.MethodOpt, node.ResultKind, node.Type));
 }
        private BoundExpression MakeUnaryOperator(
            BoundUnaryOperator oldNode,
            UnaryOperatorKind kind,
            CSharpSyntaxNode syntax,
            MethodSymbol method,
            BoundExpression loweredOperand,
            TypeSymbol type)
        {
            if (kind.IsDynamic())
            {
                Debug.Assert(kind == UnaryOperatorKind.DynamicTrue && type.SpecialType == SpecialType.System_Boolean || type.IsDynamic());
                Debug.Assert((object)method == null);

                // Logical operators on boxed Boolean constants:
                var constant = UnboxConstant(loweredOperand);
                if (constant == ConstantValue.True || constant == ConstantValue.False)
                {
                    if (kind == UnaryOperatorKind.DynamicTrue)
                    {
                        return _factory.Literal(constant.BooleanValue);
                    }
                    else if (kind == UnaryOperatorKind.DynamicLogicalNegation)
                    {
                        return MakeConversionNode(_factory.Literal(!constant.BooleanValue), type, @checked: false);
                    }
                }

                return _dynamicFactory.MakeDynamicUnaryOperator(kind, loweredOperand, type).ToExpression();
            }
            else if (kind.IsLifted())
            {
                if (!_inExpressionLambda)
                {
                    return LowerLiftedUnaryOperator(kind, syntax, method, loweredOperand, type);
                }
            }
            else if (kind.IsUserDefined())
            {
                Debug.Assert((object)method != null);
                Debug.Assert(type == method.ReturnType);
                if (!_inExpressionLambda || kind == UnaryOperatorKind.UserDefinedTrue || kind == UnaryOperatorKind.UserDefinedFalse)
                {
                    return BoundCall.Synthesized(syntax, null, method, loweredOperand);
                }
            }
            else if (kind.Operator() == UnaryOperatorKind.UnaryPlus)
            {
                // We do not call the operator even for decimal; we simply optimize it away entirely.
                return loweredOperand;
            }

            if (kind == UnaryOperatorKind.EnumBitwiseComplement)
            {
                var underlyingType = loweredOperand.Type.GetEnumUnderlyingType();
                var upconvertSpecialType = Binder.GetEnumPromotedType(underlyingType.SpecialType);
                var upconvertType = upconvertSpecialType == underlyingType.SpecialType ?
                    underlyingType :
                    _compilation.GetSpecialType(upconvertSpecialType);


                var newOperand = MakeConversionNode(loweredOperand, upconvertType, false);
                UnaryOperatorKind newKind = kind.Operator().WithType(upconvertSpecialType);

                var newNode = (oldNode != null) ?
                    oldNode.Update(
                        newKind,
                        newOperand,
                        oldNode.ConstantValueOpt,
                        method,
                        newOperand.ResultKind,
                        upconvertType) :
                    new BoundUnaryOperator(
                        syntax,
                        newKind,
                        newOperand,
                        null,
                        method,
                        LookupResultKind.Viable,
                        upconvertType);

                return MakeConversionNode(newNode.Syntax, newNode, Conversion.ExplicitEnumeration, type, @checked: false);
            }

            if (kind == UnaryOperatorKind.DecimalUnaryMinus)
            {
                method = (MethodSymbol)_compilation.Assembly.GetSpecialTypeMember(SpecialMember.System_Decimal__op_UnaryNegation);
                if (!_inExpressionLambda)
                {
                    return BoundCall.Synthesized(syntax, null, method, loweredOperand);
                }
            }

            return (oldNode != null) ?
                oldNode.Update(kind, loweredOperand, oldNode.ConstantValueOpt, method, oldNode.ResultKind, type) :
                new BoundUnaryOperator(syntax, kind, loweredOperand, null, method, LookupResultKind.Viable, type);
        }
Beispiel #14
0
        private BoundExpression MakeUnaryOperator(
            BoundUnaryOperator oldNode,
            UnaryOperatorKind kind,
            CSharpSyntaxNode syntax,
            MethodSymbol method,
            BoundExpression loweredOperand,
            TypeSymbol type)
        {
            if (kind.IsDynamic())
            {
                Debug.Assert(kind == UnaryOperatorKind.DynamicTrue && type.SpecialType == SpecialType.System_Boolean || type.IsDynamic());
                Debug.Assert((object)method == null);

                // Logical operators on boxed Boolean constants:
                var constant = UnboxConstant(loweredOperand);
                if (constant == ConstantValue.True || constant == ConstantValue.False)
                {
                    if (kind == UnaryOperatorKind.DynamicTrue)
                    {
                        return(_factory.Literal(constant.BooleanValue));
                    }
                    else if (kind == UnaryOperatorKind.DynamicLogicalNegation)
                    {
                        return(MakeConversionNode(_factory.Literal(!constant.BooleanValue), type, @checked: false));
                    }
                }

                return(_dynamicFactory.MakeDynamicUnaryOperator(kind, loweredOperand, type).ToExpression());
            }
            else if (kind.IsLifted())
            {
                if (!_inExpressionLambda)
                {
                    return(LowerLiftedUnaryOperator(kind, syntax, method, loweredOperand, type));
                }
            }
            else if (kind.IsUserDefined())
            {
                Debug.Assert((object)method != null);
                Debug.Assert(type == method.ReturnType);
                if (!_inExpressionLambda || kind == UnaryOperatorKind.UserDefinedTrue || kind == UnaryOperatorKind.UserDefinedFalse)
                {
                    // @t-mawind
                    //   As usual, concept accesses need to be rewritten down to their
                    //   default() form.
                    // Is this correct?  It's mostly a copy over from the binary case,
                    // but the unary case is different enough to make me nervous.
                    if (method is SynthesizedWitnessMethodSymbol)
                    {
                        return(BoundCall.Synthesized(syntax, SynthesizeWitnessInvocationReceiver(syntax, ((SynthesizedWitnessMethodSymbol)method).Parent), method, loweredOperand));
                    }

                    return(BoundCall.Synthesized(syntax, null, method, loweredOperand));
                }
            }
            else if (kind.Operator() == UnaryOperatorKind.UnaryPlus)
            {
                // We do not call the operator even for decimal; we simply optimize it away entirely.
                return(loweredOperand);
            }

            if (kind == UnaryOperatorKind.EnumBitwiseComplement)
            {
                var underlyingType       = loweredOperand.Type.GetEnumUnderlyingType();
                var upconvertSpecialType = Binder.GetEnumPromotedType(underlyingType.SpecialType);
                var upconvertType        = upconvertSpecialType == underlyingType.SpecialType ?
                                           underlyingType :
                                           _compilation.GetSpecialType(upconvertSpecialType);


                var newOperand            = MakeConversionNode(loweredOperand, upconvertType, false);
                UnaryOperatorKind newKind = kind.Operator().WithType(upconvertSpecialType);

                var newNode = (oldNode != null) ?
                              oldNode.Update(
                    newKind,
                    newOperand,
                    oldNode.ConstantValueOpt,
                    method,
                    newOperand.ResultKind,
                    upconvertType) :
                              new BoundUnaryOperator(
                    syntax,
                    newKind,
                    newOperand,
                    null,
                    method,
                    LookupResultKind.Viable,
                    upconvertType);

                return(MakeConversionNode(newNode.Syntax, newNode, Conversion.ExplicitEnumeration, type, @checked: false));
            }

            if (kind == UnaryOperatorKind.DecimalUnaryMinus)
            {
                method = (MethodSymbol)_compilation.Assembly.GetSpecialTypeMember(SpecialMember.System_Decimal__op_UnaryNegation);
                if (!_inExpressionLambda)
                {
                    return(BoundCall.Synthesized(syntax, null, method, loweredOperand));
                }
            }

            return((oldNode != null) ?
                   oldNode.Update(kind, loweredOperand, oldNode.ConstantValueOpt, method, oldNode.ResultKind, type) :
                   new BoundUnaryOperator(syntax, kind, loweredOperand, null, method, LookupResultKind.Viable, type));
        }
Beispiel #15
0
        private static void GetSymbolsAndResultKind(BoundUnaryOperator unaryOperator, out bool isDynamic, ref LookupResultKind resultKind, ref ImmutableArray<Symbol> symbols)
        {
            UnaryOperatorKind operandType = unaryOperator.OperatorKind.OperandTypes();
            isDynamic = unaryOperator.OperatorKind.IsDynamic();

            if (operandType == 0 || operandType == UnaryOperatorKind.UserDefined || unaryOperator.ResultKind != LookupResultKind.Viable)
            {
                if (!isDynamic)
                {
                    GetSymbolsAndResultKind(unaryOperator, unaryOperator.MethodOpt, unaryOperator.OriginalUserDefinedOperatorsOpt, out symbols, out resultKind);
                }
            }
            else
            {
                Debug.Assert((object)unaryOperator.MethodOpt == null && unaryOperator.OriginalUserDefinedOperatorsOpt.IsDefaultOrEmpty);
                UnaryOperatorKind op = unaryOperator.OperatorKind.Operator();
                symbols = ImmutableArray.Create<Symbol>(new SynthesizedIntrinsicOperatorSymbol(unaryOperator.Operand.Type.StrippedType(),
                                                                                                 OperatorFacts.UnaryOperatorNameFromOperatorKind(op),
                                                                                                 unaryOperator.Type.StrippedType(),
                                                                                                 unaryOperator.OperatorKind.IsChecked()));
                resultKind = unaryOperator.ResultKind;
            }
        }
Beispiel #16
0
 private static bool IsUserDefinedTrueOrFalse(BoundUnaryOperator @operator)
 {
     UnaryOperatorKind operatorKind = @operator.OperatorKind;
     return operatorKind == UnaryOperatorKind.UserDefinedTrue || operatorKind == UnaryOperatorKind.UserDefinedFalse;
 }
        private BoundExpression MakeBinaryOperator(
            BoundBinaryOperator oldNode,
            CSharpSyntaxNode syntax,
            BinaryOperatorKind operatorKind,
            BoundExpression loweredLeft,
            BoundExpression loweredRight,
            TypeSymbol type,
            MethodSymbol method,
            bool isPointerElementAccess = false,
            bool isCompoundAssignment = false,
            BoundUnaryOperator applyParentUnaryOperator = null)
        {
            Debug.Assert(oldNode == null || (oldNode.Syntax == syntax));

            if (_inExpressionLambda)
            {
                switch (operatorKind.Operator() | operatorKind.OperandTypes())
                {
                    case BinaryOperatorKind.ObjectAndStringConcatenation:
                    case BinaryOperatorKind.StringAndObjectConcatenation:
                    case BinaryOperatorKind.StringConcatenation:
                        return RewriteStringConcatenation(syntax, operatorKind, loweredLeft, loweredRight, type);
                    case BinaryOperatorKind.DelegateCombination:
                        return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__Combine);
                    case BinaryOperatorKind.DelegateRemoval:
                        return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__Remove);
                    case BinaryOperatorKind.DelegateEqual:
                        return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__op_Equality);
                    case BinaryOperatorKind.DelegateNotEqual:
                        return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__op_Inequality);
                }
            }
            else
            // try to lower the expression.
            {
                if (operatorKind.IsDynamic())
                {
                    Debug.Assert(!isPointerElementAccess);

                    if (operatorKind.IsLogical())
                    {
                        return MakeDynamicLogicalBinaryOperator(syntax, operatorKind, loweredLeft, loweredRight, method, type, isCompoundAssignment, applyParentUnaryOperator);
                    }
                    else
                    {
                        Debug.Assert((object)method == null);
                        return _dynamicFactory.MakeDynamicBinaryOperator(operatorKind, loweredLeft, loweredRight, isCompoundAssignment, type).ToExpression();
                    }
                }

                if (operatorKind.IsLifted())
                {
                    return RewriteLiftedBinaryOperator(syntax, operatorKind, loweredLeft, loweredRight, type, method);
                }

                if (operatorKind.IsUserDefined())
                {
                    return LowerUserDefinedBinaryOperator(syntax, operatorKind, loweredLeft, loweredRight, type, method);
                }

                switch (operatorKind.OperatorWithLogical() | operatorKind.OperandTypes())
                {
                    case BinaryOperatorKind.NullableNullEqual:
                    case BinaryOperatorKind.NullableNullNotEqual:
                        return RewriteNullableNullEquality(syntax, operatorKind, loweredLeft, loweredRight, type);

                    case BinaryOperatorKind.ObjectAndStringConcatenation:
                    case BinaryOperatorKind.StringAndObjectConcatenation:
                    case BinaryOperatorKind.StringConcatenation:
                        return RewriteStringConcatenation(syntax, operatorKind, loweredLeft, loweredRight, type);

                    case BinaryOperatorKind.StringEqual:
                        return RewriteStringEquality(oldNode, syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_String__op_Equality);

                    case BinaryOperatorKind.StringNotEqual:
                        return RewriteStringEquality(oldNode, syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_String__op_Inequality);

                    case BinaryOperatorKind.DelegateCombination:
                        return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__Combine);

                    case BinaryOperatorKind.DelegateRemoval:
                        return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__Remove);

                    case BinaryOperatorKind.DelegateEqual:
                        return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__op_Equality);

                    case BinaryOperatorKind.DelegateNotEqual:
                        return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__op_Inequality);

                    case BinaryOperatorKind.LogicalBoolAnd:
                        if (loweredRight.ConstantValue == ConstantValue.True) return loweredLeft;
                        if (loweredLeft.ConstantValue == ConstantValue.True) return loweredRight;
                        if (loweredLeft.ConstantValue == ConstantValue.False) return loweredLeft;

                        if (loweredRight.Kind == BoundKind.Local || loweredRight.Kind == BoundKind.Parameter)
                        {
                            operatorKind &= ~BinaryOperatorKind.Logical;
                        }

                        goto default;

                    case BinaryOperatorKind.LogicalBoolOr:
                        if (loweredRight.ConstantValue == ConstantValue.False) return loweredLeft;
                        if (loweredLeft.ConstantValue == ConstantValue.False) return loweredRight;
                        if (loweredLeft.ConstantValue == ConstantValue.True) return loweredLeft;

                        if (loweredRight.Kind == BoundKind.Local || loweredRight.Kind == BoundKind.Parameter)
                        {
                            operatorKind &= ~BinaryOperatorKind.Logical;
                        }

                        goto default;

                    case BinaryOperatorKind.BoolAnd:
                        if (loweredRight.ConstantValue == ConstantValue.True) return loweredLeft;
                        if (loweredLeft.ConstantValue == ConstantValue.True) return loweredRight;
                        goto default;

                    case BinaryOperatorKind.BoolOr:
                        if (loweredRight.ConstantValue == ConstantValue.False) return loweredLeft;
                        if (loweredLeft.ConstantValue == ConstantValue.False) return loweredRight;
                        goto default;

                    case BinaryOperatorKind.BoolEqual:
                        if (loweredLeft.ConstantValue == ConstantValue.True) return loweredRight;
                        if (loweredRight.ConstantValue == ConstantValue.True) return loweredLeft;

                        if (loweredLeft.ConstantValue == ConstantValue.False)
                            return MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, null, loweredRight, loweredRight.Type);

                        if (loweredRight.ConstantValue == ConstantValue.False)
                            return MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, null, loweredLeft, loweredLeft.Type);

                        goto default;

                    case BinaryOperatorKind.BoolNotEqual:
                        if (loweredLeft.ConstantValue == ConstantValue.False) return loweredRight;
                        if (loweredRight.ConstantValue == ConstantValue.False) return loweredLeft;

                        if (loweredLeft.ConstantValue == ConstantValue.True)
                            return MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, null, loweredRight, loweredRight.Type);

                        if (loweredRight.ConstantValue == ConstantValue.True)
                            return MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, null, loweredLeft, loweredLeft.Type);

                        goto default;

                    case BinaryOperatorKind.BoolXor:
                        if (loweredLeft.ConstantValue == ConstantValue.False) return loweredRight;
                        if (loweredRight.ConstantValue == ConstantValue.False) return loweredLeft;

                        if (loweredLeft.ConstantValue == ConstantValue.True)
                            return MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, null, loweredRight, loweredRight.Type);

                        if (loweredRight.ConstantValue == ConstantValue.True)
                            return MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, null, loweredLeft, loweredLeft.Type);

                        goto default;

                    case BinaryOperatorKind.IntLeftShift:
                    case BinaryOperatorKind.UIntLeftShift:
                    case BinaryOperatorKind.IntRightShift:
                    case BinaryOperatorKind.UIntRightShift:
                        return RewriteBuiltInShiftOperation(oldNode, syntax, operatorKind, loweredLeft, loweredRight, type, 0x1F);

                    case BinaryOperatorKind.LongLeftShift:
                    case BinaryOperatorKind.ULongLeftShift:
                    case BinaryOperatorKind.LongRightShift:
                    case BinaryOperatorKind.ULongRightShift:
                        return RewriteBuiltInShiftOperation(oldNode, syntax, operatorKind, loweredLeft, loweredRight, type, 0x3F);

                    case BinaryOperatorKind.DecimalAddition:
                    case BinaryOperatorKind.DecimalSubtraction:
                    case BinaryOperatorKind.DecimalMultiplication:
                    case BinaryOperatorKind.DecimalDivision:
                    case BinaryOperatorKind.DecimalRemainder:
                    case BinaryOperatorKind.DecimalEqual:
                    case BinaryOperatorKind.DecimalNotEqual:
                    case BinaryOperatorKind.DecimalLessThan:
                    case BinaryOperatorKind.DecimalLessThanOrEqual:
                    case BinaryOperatorKind.DecimalGreaterThan:
                    case BinaryOperatorKind.DecimalGreaterThanOrEqual:
                        return RewriteDecimalBinaryOperation(syntax, loweredLeft, loweredRight, operatorKind);

                    case BinaryOperatorKind.PointerAndIntAddition:
                    case BinaryOperatorKind.PointerAndUIntAddition:
                    case BinaryOperatorKind.PointerAndLongAddition:
                    case BinaryOperatorKind.PointerAndULongAddition:
                    case BinaryOperatorKind.PointerAndIntSubtraction:
                    case BinaryOperatorKind.PointerAndUIntSubtraction:
                    case BinaryOperatorKind.PointerAndLongSubtraction:
                    case BinaryOperatorKind.PointerAndULongSubtraction:
                        if (loweredRight.IsDefaultValue())
                        {
                            return loweredLeft;
                        }
                        return RewritePointerNumericOperator(syntax, operatorKind, loweredLeft, loweredRight, type, isPointerElementAccess, isLeftPointer: true);

                    case BinaryOperatorKind.IntAndPointerAddition:
                    case BinaryOperatorKind.UIntAndPointerAddition:
                    case BinaryOperatorKind.LongAndPointerAddition:
                    case BinaryOperatorKind.ULongAndPointerAddition:
                        if (loweredLeft.IsDefaultValue())
                        {
                            return loweredRight;
                        }
                        return RewritePointerNumericOperator(syntax, operatorKind, loweredLeft, loweredRight, type, isPointerElementAccess, isLeftPointer: false);

                    case BinaryOperatorKind.PointerSubtraction:
                        return RewritePointerSubtraction(operatorKind, loweredLeft, loweredRight, type);

                    case BinaryOperatorKind.IntAddition:
                    case BinaryOperatorKind.UIntAddition:
                    case BinaryOperatorKind.LongAddition:
                    case BinaryOperatorKind.ULongAddition:
                        if (loweredLeft.IsDefaultValue())
                        {
                            return loweredRight;
                        }
                        if (loweredRight.IsDefaultValue())
                        {
                            return loweredLeft;
                        }
                        goto default;

                    case BinaryOperatorKind.IntSubtraction:
                    case BinaryOperatorKind.LongSubtraction:
                    case BinaryOperatorKind.UIntSubtraction:
                    case BinaryOperatorKind.ULongSubtraction:
                        if (loweredRight.IsDefaultValue())
                        {
                            return loweredLeft;
                        }
                        goto default;

                    case BinaryOperatorKind.IntMultiplication:
                    case BinaryOperatorKind.LongMultiplication:
                    case BinaryOperatorKind.UIntMultiplication:
                    case BinaryOperatorKind.ULongMultiplication:
                        if (loweredLeft.IsDefaultValue())
                        {
                            return loweredLeft;
                        }
                        if (loweredRight.IsDefaultValue())
                        {
                            return loweredRight;
                        }
                        if (loweredLeft.ConstantValue?.UInt64Value == 1)
                        {
                            return loweredRight;
                        }
                        if (loweredRight.ConstantValue?.UInt64Value == 1)
                        {
                            return loweredLeft;
                        }
                        goto default;

                    case BinaryOperatorKind.IntGreaterThan:
                    case BinaryOperatorKind.IntLessThanOrEqual:
                        if (loweredLeft.Kind == BoundKind.ArrayLength && loweredRight.IsDefaultValue())
                        {
                            //array length is never negative
                            var newOp = operatorKind == BinaryOperatorKind.IntGreaterThan ?
                                                        BinaryOperatorKind.NotEqual :
                                                        BinaryOperatorKind.Equal;

                            operatorKind &= ~BinaryOperatorKind.OpMask;
                            operatorKind |= newOp;
                            loweredLeft = UnconvertArrayLength((BoundArrayLength)loweredLeft);
                        }
                        goto default;

                    case BinaryOperatorKind.IntLessThan:
                    case BinaryOperatorKind.IntGreaterThanOrEqual:
                        if (loweredRight.Kind == BoundKind.ArrayLength && loweredLeft.IsDefaultValue())
                        {
                            //array length is never negative
                            var newOp = operatorKind == BinaryOperatorKind.IntLessThan ?
                                                        BinaryOperatorKind.NotEqual :
                                                        BinaryOperatorKind.Equal;

                            operatorKind &= ~BinaryOperatorKind.OpMask;
                            operatorKind |= newOp;
                            loweredRight = UnconvertArrayLength((BoundArrayLength)loweredRight);
                        }
                        goto default;

                    case BinaryOperatorKind.IntEqual:
                    case BinaryOperatorKind.IntNotEqual:
                        if (loweredLeft.Kind == BoundKind.ArrayLength && loweredRight.IsDefaultValue())
                        {
                            loweredLeft = UnconvertArrayLength((BoundArrayLength)loweredLeft);
                        }
                        else if (loweredRight.Kind == BoundKind.ArrayLength && loweredLeft.IsDefaultValue())
                        {
                            loweredRight = UnconvertArrayLength((BoundArrayLength)loweredRight);
                        }

                        goto default;

                    default:
                        break;
                }
            }

            return (oldNode != null) ?
                oldNode.Update(operatorKind, loweredLeft, loweredRight, oldNode.ConstantValueOpt, oldNode.MethodOpt, oldNode.ResultKind, type) :
                new BoundBinaryOperator(syntax, operatorKind, loweredLeft, loweredRight, null, null, LookupResultKind.Viable, type);
        }
        private BoundExpression VisitUnaryOperator(BoundUnaryOperator node)
        {
            var arg = node.Operand;
            var loweredArg = Visit(arg);
            var opKind = node.OperatorKind;
            var op = opKind & UnaryOperatorKind.OpMask;
            var isChecked = (opKind & UnaryOperatorKind.Checked) != 0;

            string opname;
            switch (op)
            {
                case UnaryOperatorKind.UnaryPlus:
                    if ((object)node.MethodOpt == null)
                    {
                        return loweredArg;
                    }
                    opname = "UnaryPlus";
                    break;
                case UnaryOperatorKind.UnaryMinus:
                    opname = isChecked ? "NegateChecked" : "Negate";
                    break;
                case UnaryOperatorKind.BitwiseComplement:
                case UnaryOperatorKind.LogicalNegation:
                    opname = "Not";
                    break;
                default:
                    throw ExceptionUtilities.UnexpectedValue(op);
            }

            if (node.OperatorKind.OperandTypes() == UnaryOperatorKind.Enum && (opKind & UnaryOperatorKind.Lifted) != 0)
            {
                Debug.Assert((object)node.MethodOpt == null);
                var promotedType = PromotedType(arg.Type.StrippedType().GetEnumUnderlyingType());
                promotedType = _nullableType.Construct(promotedType);
                loweredArg = Convert(loweredArg, arg.Type, promotedType, isChecked, false);
                var result = ExprFactory(opname, loweredArg);
                return Demote(result, node.Type, isChecked);
            }

            return ((object)node.MethodOpt == null)
                ? ExprFactory(opname, loweredArg)
                : ExprFactory(opname, loweredArg, _bound.MethodInfo(node.MethodOpt));
        }
        private void CheckLiftedUnaryOp(BoundUnaryOperator node)
        {
            Debug.Assert(node != null);

            if (!node.OperatorKind.IsLifted())
            {
                return;
            }

            // CS0458: The result of the expression is always 'null' of type '{0}'
            if (node.Operand.NullableNeverHasValue())
            {
                Error(ErrorCode.WRN_AlwaysNull, node, node.Type);
            }
        }
Beispiel #20
0
        private BoundExpression MakeUnaryOperator(
            BoundUnaryOperator oldNode,
            UnaryOperatorKind kind,
            SyntaxNode syntax,
            MethodSymbol method,
            BoundExpression loweredOperand,
            TypeSymbol type)
        {
            if (kind.IsDynamic())
            {
                Debug.Assert(kind == UnaryOperatorKind.DynamicTrue && type.SpecialType == SpecialType.System_Boolean || type.IsDynamic());
                Debug.Assert((object)method == null);

                // Logical operators on boxed Boolean constants:
                var constant = UnboxConstant(loweredOperand);
                if (constant == ConstantValue.True || constant == ConstantValue.False)
                {
                    if (kind == UnaryOperatorKind.DynamicTrue)
                    {
                        return(_factory.Literal(constant.BooleanValue));
                    }
                    else if (kind == UnaryOperatorKind.DynamicLogicalNegation)
                    {
                        return(MakeConversionNode(_factory.Literal(!constant.BooleanValue), type, @checked: false));
                    }
                }

                return(_dynamicFactory.MakeDynamicUnaryOperator(kind, loweredOperand, type).ToExpression());
            }
            else if (kind.IsLifted())
            {
                if (!_inExpressionLambda)
                {
                    return(LowerLiftedUnaryOperator(kind, syntax, method, loweredOperand, type));
                }
            }
            else if (kind.IsUserDefined())
            {
                Debug.Assert((object)method != null);
                Debug.Assert(type == method.ReturnType);
                if (!_inExpressionLambda || kind == UnaryOperatorKind.UserDefinedTrue || kind == UnaryOperatorKind.UserDefinedFalse)
                {
                    return(BoundCall.Synthesized(syntax, null, method, loweredOperand));
                }
            }
            else if (kind.Operator() == UnaryOperatorKind.UnaryPlus)
            {
                // We do not call the operator even for decimal; we simply optimize it away entirely.
                return(loweredOperand);
            }

            if (kind == UnaryOperatorKind.EnumBitwiseComplement)
            {
                var underlyingType       = loweredOperand.Type.GetEnumUnderlyingType();
                var upconvertSpecialType = Binder.GetEnumPromotedType(underlyingType.SpecialType);
                var upconvertType        = upconvertSpecialType == underlyingType.SpecialType ?
                                           underlyingType :
                                           _compilation.GetSpecialType(upconvertSpecialType);


                var newOperand            = MakeConversionNode(loweredOperand, upconvertType, false);
                UnaryOperatorKind newKind = kind.Operator().WithType(upconvertSpecialType);

                var newNode = (oldNode != null) ?
                              oldNode.Update(
                    newKind,
                    newOperand,
                    oldNode.ConstantValueOpt,
                    method,
                    newOperand.ResultKind,
                    upconvertType) :
                              new BoundUnaryOperator(
                    syntax,
                    newKind,
                    newOperand,
                    null,
                    method,
                    LookupResultKind.Viable,
                    upconvertType);

                return(MakeConversionNode(newNode.Syntax, newNode, Conversion.ExplicitEnumeration, type, @checked: false));
            }

            if (kind == UnaryOperatorKind.DecimalUnaryMinus)
            {
                method = (MethodSymbol)_compilation.Assembly.GetSpecialTypeMember(SpecialMember.System_Decimal__op_UnaryNegation);
                if (!_inExpressionLambda)
                {
                    return(BoundCall.Synthesized(syntax, null, method, loweredOperand));
                }
            }

            return((oldNode != null) ?
                   oldNode.Update(kind, loweredOperand, oldNode.ConstantValueOpt, method, oldNode.ResultKind, type) :
                   new BoundUnaryOperator(syntax, kind, loweredOperand, null, method, LookupResultKind.Viable, type));
        }
 private void CheckDynamic(BoundUnaryOperator node)
 {
     if (_inExpressionLambda && node.OperatorKind.IsDynamic())
     {
         Error(ErrorCode.ERR_ExpressionTreeContainsDynamicOperation, node);
     }
 }
        private BoundExpression MakeDynamicLogicalBinaryOperator(
            CSharpSyntaxNode syntax,
            BinaryOperatorKind operatorKind,
            BoundExpression loweredLeft,
            BoundExpression loweredRight,
            MethodSymbol leftTruthOperator,
            TypeSymbol type,
            bool isCompoundAssignment,
            BoundUnaryOperator applyParentUnaryOperator)
        {
            Debug.Assert(operatorKind.Operator() == BinaryOperatorKind.And || operatorKind.Operator() == BinaryOperatorKind.Or);

            // Dynamic logical && and || operators are lowered as follows:
            //   left && right  ->  IsFalse(left) ? left : And(left, right)
            //   left || right  ->  IsTrue(left) ? left : Or(left, right)
            // 
            // Optimization: If the binary AND/OR is directly contained in IsFalse/IsTrue operator (parentUnaryOperator != null)
            // we can avoid calling IsFalse/IsTrue twice on the same object.
            //   IsFalse(left && right)  ->  IsFalse(left) || IsFalse(And(left, right))
            //   IsTrue(left || right)   ->  IsTrue(left) || IsTrue(Or(left, right))

            bool isAnd = operatorKind.Operator() == BinaryOperatorKind.And;

            // Operator to be used to test the left operand:
            var testOperator = isAnd ? UnaryOperatorKind.DynamicFalse : UnaryOperatorKind.DynamicTrue;

            // VisitUnaryOperator ensures we are never called with parentUnaryOperator != null when we can't perform the optimization.
            Debug.Assert(applyParentUnaryOperator == null || applyParentUnaryOperator.OperatorKind == testOperator);

            ConstantValue constantLeft = loweredLeft.ConstantValue ?? UnboxConstant(loweredLeft);
            if (testOperator == UnaryOperatorKind.DynamicFalse && constantLeft == ConstantValue.False ||
                testOperator == UnaryOperatorKind.DynamicTrue && constantLeft == ConstantValue.True)
            {
                Debug.Assert(leftTruthOperator == null);

                if (applyParentUnaryOperator != null)
                {
                    // IsFalse(false && right) -> true
                    // IsTrue(true || right)   -> true
                    return _factory.Literal(true);
                }
                else
                {
                    // false && right  ->  box(false)
                    // true || right   ->  box(true)
                    return MakeConversionNode(loweredLeft, type, @checked: false);
                }
            }

            BoundExpression result;
            var boolean = _compilation.GetSpecialType(SpecialType.System_Boolean);

            // Store left to local if needed. If constant or already local we don't need a temp 
            // since the value of left can't change until right is evaluated.
            BoundAssignmentOperator tempAssignment;
            BoundLocal temp;
            if (constantLeft == null && loweredLeft.Kind != BoundKind.Local && loweredLeft.Kind != BoundKind.Parameter)
            {
                BoundAssignmentOperator assignment;
                var local = _factory.StoreToTemp(loweredLeft, out assignment);
                loweredLeft = local;
                tempAssignment = assignment;
                temp = local;
            }
            else
            {
                tempAssignment = null;
                temp = null;
            }

            var op = _dynamicFactory.MakeDynamicBinaryOperator(operatorKind, loweredLeft, loweredRight, isCompoundAssignment, type).ToExpression();

            // IsFalse(true) or IsTrue(false) are always false:
            bool leftTestIsConstantFalse = testOperator == UnaryOperatorKind.DynamicFalse && constantLeft == ConstantValue.True ||
                                           testOperator == UnaryOperatorKind.DynamicTrue && constantLeft == ConstantValue.False;

            if (applyParentUnaryOperator != null)
            {
                // IsFalse(left && right)  ->  IsFalse(left) || IsFalse(And(left, right))
                // IsTrue(left || right)   ->  IsTrue(left) || IsTrue(Or(left, right))

                result = _dynamicFactory.MakeDynamicUnaryOperator(testOperator, op, boolean).ToExpression();
                if (!leftTestIsConstantFalse)
                {
                    BoundExpression leftTest = MakeTruthTestForDynamicLogicalOperator(syntax, loweredLeft, boolean, leftTruthOperator, negative: isAnd);
                    result = _factory.Binary(BinaryOperatorKind.LogicalOr, boolean, leftTest, result);
                }
            }
            else
            {
                // left && right  ->  IsFalse(left) ? left : And(left, right)
                // left || right  ->  IsTrue(left) ? left : Or(left, right)

                if (leftTestIsConstantFalse)
                {
                    result = op;
                }
                else
                {
                    // We might need to box.
                    BoundExpression leftTest = MakeTruthTestForDynamicLogicalOperator(syntax, loweredLeft, boolean, leftTruthOperator, negative: isAnd);
                    var convertedLeft = MakeConversionNode(loweredLeft, type, @checked: false);
                    result = _factory.Conditional(leftTest, convertedLeft, op, type);
                }
            }

            if (tempAssignment != null)
            {
                return _factory.Sequence(ImmutableArray.Create(temp.LocalSymbol), ImmutableArray.Create<BoundExpression>(tempAssignment), result);
            }

            return result;
        }
 public override BoundNode VisitUnaryOperator(BoundUnaryOperator node)
 {
     CheckUnsafeType(node);
     CheckLiftedUnaryOp(node);
     CheckDynamic(node);
     return base.VisitUnaryOperator(node);
 }