Beispiel #1
0
        private static bool IsConditional(BinaryOperatorKind opKind)
        {
            switch (opKind.OperatorWithLogical())
            {
            case BinaryOperatorKind.LogicalAnd:
            case BinaryOperatorKind.LogicalOr:
            case BinaryOperatorKind.Equal:
            case BinaryOperatorKind.NotEqual:
            case BinaryOperatorKind.LessThan:
            case BinaryOperatorKind.LessThanOrEqual:
            case BinaryOperatorKind.GreaterThan:
            case BinaryOperatorKind.GreaterThanOrEqual:
                return(true);

            case BinaryOperatorKind.And:
            case BinaryOperatorKind.Or:
            case BinaryOperatorKind.Xor:
                return(opKind.OperandTypes() == BinaryOperatorKind.Bool);
            }

            return(false);
        }
        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 void GetAllBuiltInOperators(BinaryOperatorKind kind, BoundExpression left, BoundExpression right, ArrayBuilder<BinaryOperatorAnalysisResult> results, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            // Strip the "checked" off; the checked-ness of the context does not affect which built-in operators
            // are applicable.
            kind = kind.OperatorWithLogical();
            var operators = ArrayBuilder<BinaryOperatorSignature>.GetInstance();
            bool isEquality = kind == BinaryOperatorKind.Equal || kind == BinaryOperatorKind.NotEqual;
            if (isEquality && UseOnlyReferenceEquality(left, right, ref useSiteDiagnostics))
            {
                // As a special case, if the reference equality operator is applicable (and it
                // is not a string or delegate) we do not check any other operators.  This patches
                // what is otherwise a flaw in the language specification.  See 11426.
                GetReferenceEquality(kind, operators);
            }
            else
            {
                this.Compilation.builtInOperators.GetSimpleBuiltInOperators(kind, operators);

                // SPEC 7.3.4: For predefined enum and delegate operators, the only operators
                // considered are those defined by an enum or delegate type that is the binding
                //-time type of one of the operands.
                GetDelegateOperations(kind, left, right, operators, ref useSiteDiagnostics);
                GetEnumOperations(kind, left, right, operators);

                // We similarly limit pointer operator candidates considered.
                GetPointerOperators(kind, left, right, operators);
            }

            CandidateOperators(operators, left, right, results, ref useSiteDiagnostics);
            operators.Free();
        }
Beispiel #4
0
        private static bool IsConditional(BinaryOperatorKind opKind)
        {
            switch (opKind.OperatorWithLogical())
            {
                case BinaryOperatorKind.LogicalAnd:
                case BinaryOperatorKind.LogicalOr:
                case BinaryOperatorKind.Equal:
                case BinaryOperatorKind.NotEqual:
                case BinaryOperatorKind.LessThan:
                case BinaryOperatorKind.LessThanOrEqual:
                case BinaryOperatorKind.GreaterThan:
                case BinaryOperatorKind.GreaterThanOrEqual:
                    return true;

                case BinaryOperatorKind.And:
                case BinaryOperatorKind.Or:
                case BinaryOperatorKind.Xor:
                    return opKind.OperandTypes() == BinaryOperatorKind.Bool;
            }

            return false;
        }
        private void GetAllBuiltInOperators(BinaryOperatorKind kind, BoundExpression left, BoundExpression right, ArrayBuilder<BinaryOperatorAnalysisResult> results, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            // Strip the "checked" off; the checked-ness of the context does not affect which built-in operators
            // are applicable.
            kind = kind.OperatorWithLogical();

            // The spec states that overload resolution is performed upon the infinite set of
            // operators defined on enumerated types, pointers and delegates. Clearly we cannot
            // construct the infinite set; we have to pare it down. Previous implementations of C#
            // implement a much stricter rule; they only add the special operators to the candidate
            // set if one of the operands is of the relevant type. This means that operands
            // involving user-defined implicit conversions from class or struct types to enum,
            // pointer and delegate types do not cause the right candidates to participate in
            // overload resolution. It also presents numerous problems involving delegate variance
            // and conversions from lambdas to delegate types.
            //
            // It is onerous to require the actually specified behavior. We should change the
            // specification to match the previous implementation.

            var operators = ArrayBuilder<BinaryOperatorSignature>.GetInstance();
            bool isEquality = kind == BinaryOperatorKind.Equal || kind == BinaryOperatorKind.NotEqual;
            if (isEquality && UseOnlyReferenceEquality(left, right, ref useSiteDiagnostics))
            {
                // As a special case, if the reference equality operator is applicable (and it
                // is not a string or delegate) we do not check any other operators.  This patches
                // what is otherwise a flaw in the language specification.  See 11426.
                GetReferenceEquality(kind, operators);
            }
            else
            {
                this.Compilation.builtInOperators.GetSimpleBuiltInOperators(kind, operators);
                GetDelegateOperations(kind, left, right, operators, ref useSiteDiagnostics);
                GetEnumOperations(kind, left, right, operators);
                GetPointerOperators(kind, left, right, operators);
            }

            CandidateOperators(operators, left, right, results, ref useSiteDiagnostics);
            operators.Free();
        }