示例#1
0
        /// <summary>
        /// Produce an element-wise comparison and logic to ensure the result is a bool type.
        ///
        /// If an element-wise comparison doesn't return bool, then:
        /// - if it is dynamic, we'll do <c>!(comparisonResult.false)</c> or <c>comparisonResult.true</c>
        /// - if it implicitly converts to bool, we'll just do the conversion
        /// - otherwise, we'll do <c>!(comparisonResult.false)</c> or <c>comparisonResult.true</c> (as we'd do for <c>if</c> or <c>while</c>)
        /// </summary>
        private BoundExpression RewriteTupleSingleOperator(TupleBinaryOperatorInfo.Single single,
                                                           BoundExpression left, BoundExpression right, TypeSymbol boolType, BinaryOperatorKind operatorKind)
        {
            if (left.IsLiteralNull() && right.IsLiteralNull())
            {
                // For `null == null` this is special-cased during initial binding
                return(new BoundLiteral(left.Syntax, ConstantValue.Create(operatorKind == BinaryOperatorKind.Equal), boolType));
            }

            // We leave both operands in nullable-null conversions unconverted, MakeBinaryOperator has special for null-literal
            bool            isNullableNullConversion = single.Kind.OperandTypes() == BinaryOperatorKind.NullableNull;
            BoundExpression convertedLeft            = isNullableNullConversion
                ? left
                : MakeConversionNode(left.Syntax, left, single.LeftConversion, single.LeftConvertedTypeOpt, @checked: false);

            BoundExpression convertedRight = isNullableNullConversion
                ? right
                : MakeConversionNode(right.Syntax, right, single.RightConversion, single.RightConvertedTypeOpt, @checked: false);

            BoundExpression        binary         = MakeBinaryOperator(_factory.Syntax, single.Kind, convertedLeft, convertedRight, single.MethodSymbolOpt?.ReturnType.TypeSymbol ?? boolType, single.MethodSymbolOpt);
            UnaryOperatorSignature boolOperator   = single.BoolOperator;
            Conversion             boolConversion = single.ConversionForBool;

            BoundExpression result;

            if (boolOperator.Kind != UnaryOperatorKind.Error)
            {
                // Produce
                // !((left == right).op_false)
                // (left != right).op_true
                BoundExpression convertedBinary = MakeConversionNode(_factory.Syntax, binary, boolConversion, boolOperator.OperandType, @checked: false);

                Debug.Assert(boolOperator.ReturnType.SpecialType == SpecialType.System_Boolean);
                result = MakeUnaryOperator(boolOperator.Kind, binary.Syntax, boolOperator.Method, convertedBinary, boolType);

                if (operatorKind == BinaryOperatorKind.Equal)
                {
                    result = _factory.Not(result);
                }
            }
            else if (!boolConversion.IsIdentity)
            {
                // Produce
                // (bool)(left == right)
                // (bool)(left != right)
                result = MakeConversionNode(_factory.Syntax, binary, boolConversion, boolType, @checked: false);
            }
            else
            {
                result = binary;
            }

            return(result);
        }
示例#2
0
        private BoundExpression VisitBinaryOperator(BinaryOperatorKind opKind, MethodSymbol methodOpt, TypeSymbol type, BoundExpression left, BoundExpression right)
        {
            bool   isChecked, isLifted, requiresLifted;
            string opName = GetBinaryOperatorName(opKind, out isChecked, out isLifted, out requiresLifted);

            // Fix up the null value for a nullable comparison vs null
            if ((object)left.Type == null && left.IsLiteralNull())
            {
                left = _bound.Default(right.Type);
            }
            if ((object)right.Type == null && right.IsLiteralNull())
            {
                right = _bound.Default(left.Type);
            }


            // Enums are handled as per their promoted underlying type
            switch (opKind.OperandTypes())
            {
            case BinaryOperatorKind.EnumAndUnderlying:
            case BinaryOperatorKind.UnderlyingAndEnum:
            case BinaryOperatorKind.Enum:
            {
                var enumOperand  = (opKind.OperandTypes() == BinaryOperatorKind.UnderlyingAndEnum) ? right : left;
                var promotedType = PromotedType(enumOperand.Type.StrippedType().GetEnumUnderlyingType());
                if (opKind.IsLifted())
                {
                    promotedType = _nullableType.Construct(promotedType);
                }

                var loweredLeft  = VisitAndPromoteEnumOperand(left, promotedType, isChecked);
                var loweredRight = VisitAndPromoteEnumOperand(right, promotedType, isChecked);

                var result = MakeBinary(methodOpt, type, isLifted, requiresLifted, opName, loweredLeft, loweredRight);
                return(Demote(result, type, isChecked));
            }

            default:
            {
                var loweredLeft  = Visit(left);
                var loweredRight = Visit(right);
                return(MakeBinary(methodOpt, type, isLifted, requiresLifted, opName, loweredLeft, loweredRight));
            }
            }
        }
示例#3
0
 public static bool IsLiteralNullOrDefault(this BoundExpression node)
 {
     return(node.IsLiteralNull() || node.IsLiteralDefault());
 }