) As BoundExpression

in src/Compilers/VisualBasic/Portable/Binding/Binder_Operators.vb [205:545]


        ) As BoundExpression

            Debug.Assert(left.IsValue)
            Debug.Assert(right.IsValue)

            Dim originalDiagnostics = diagnostics

            If (left.HasErrors OrElse right.HasErrors) Then
                
                diagnostics = New DiagnosticBag()
            End If

            
            ConvertNothingLiterals(preliminaryOperatorKind, left, right, diagnostics)

            left = MakeRValue(left, diagnostics)
            right = MakeRValue(right, diagnostics)

            If (left.HasErrors OrElse right.HasErrors) Then
                
                If diagnostics Is originalDiagnostics Then
                    diagnostics = New DiagnosticBag()
                End If
            End If

            Dim leftType As TypeSymbol = left.Type
            Dim rightType As TypeSymbol = right.Type

            Dim leftIsDBNull As Boolean = leftType.IsDBNullType()
            Dim rightIsDBNull As Boolean = rightType.IsDBNullType()

            
            
            If (preliminaryOperatorKind = BinaryOperatorKind.Concatenate AndAlso leftIsDBNull <> rightIsDBNull) OrElse
               (preliminaryOperatorKind = BinaryOperatorKind.Add AndAlso
                  ((leftType.IsStringType() AndAlso rightIsDBNull) OrElse (leftIsDBNull AndAlso rightType.IsStringType))) Then

                Debug.Assert(leftIsDBNull Xor rightIsDBNull)

                If leftIsDBNull Then
                    leftType = SubstituteDBNullWithNothingString(left, rightType, diagnostics)
                Else
                    rightType = SubstituteDBNullWithNothingString(right, leftType, diagnostics)
                End If
            End If

            
            
            
            
            
            Dim intrinsicOperatorType As SpecialType = SpecialType.None
            Dim userDefinedOperator As OverloadResolution.OverloadResolutionResult = Nothing
            Dim useSiteDiagnostics As HashSet(Of DiagnosticInfo) = Nothing
            Dim operatorKind As BinaryOperatorKind = OverloadResolution.ResolveBinaryOperator(preliminaryOperatorKind, left, right, Me,
                                                                                              True,
                                                                                              intrinsicOperatorType,
                                                                                              userDefinedOperator,
                                                                                              useSiteDiagnostics)

            If diagnostics.Add(node, useSiteDiagnostics) Then
                
                diagnostics = New DiagnosticBag()
            End If

            If operatorKind = BinaryOperatorKind.UserDefined Then
                Dim bestCandidate As OverloadResolution.Candidate = If(userDefinedOperator.BestResult.HasValue,
                                                                       userDefinedOperator.BestResult.Value.Candidate,
                                                                       Nothing)
                If bestCandidate Is Nothing OrElse
                   Not bestCandidate.IsLifted OrElse
                   (OverloadResolution.IsValidInLiftedSignature(bestCandidate.Parameters(0).Type) AndAlso
                    OverloadResolution.IsValidInLiftedSignature(bestCandidate.Parameters(1).Type) AndAlso
                    OverloadResolution.IsValidInLiftedSignature(bestCandidate.ReturnType)) Then

                    If preliminaryOperatorKind = BinaryOperatorKind.AndAlso OrElse preliminaryOperatorKind = BinaryOperatorKind.OrElse Then
                        Return BindUserDefinedShortCircuitingOperator(node, preliminaryOperatorKind, left, right,
                                                                      userDefinedOperator, diagnostics)
                    Else
                        Return BindUserDefinedNonShortCircuitingBinaryOperator(node, preliminaryOperatorKind, left, right,
                                                                               userDefinedOperator, diagnostics)
                    End If
                End If

                operatorKind = BinaryOperatorKind.Error
            End If

            If operatorKind = BinaryOperatorKind.Error Then
                ReportUndefinedOperatorError(node, left, right, operatorTokenKind, preliminaryOperatorKind, diagnostics)

                Return New BoundBinaryOperator(node, preliminaryOperatorKind Or BinaryOperatorKind.Error, left, right, CheckOverflow, ErrorTypeSymbol.UnknownResultType, hasErrors:=True)
            End If

            

            
            Dim operandType As TypeSymbol

            If intrinsicOperatorType = SpecialType.None Then
                
                Debug.Assert(leftType.GetNullableUnderlyingTypeOrSelf().IsEnumType() AndAlso
                             leftType.GetNullableUnderlyingTypeOrSelf().IsSameTypeIgnoringAll(rightType.GetNullableUnderlyingTypeOrSelf()))

                If (operatorKind And BinaryOperatorKind.Lifted) = 0 OrElse leftType.IsNullableType() Then
                    operandType = leftType
                Else
                    Debug.Assert(rightType.IsNullableType())
                    operandType = rightType
                End If

            Else
                operandType = GetSpecialTypeForBinaryOperator(node, leftType, rightType, intrinsicOperatorType,
                                                              (operatorKind And BinaryOperatorKind.Lifted) <> 0, diagnostics)
            End If

            
            Dim operatorResultType As TypeSymbol = operandType

            Dim forceToBooleanType As TypeSymbol = Nothing
            Dim applyIsTrue As Boolean = False

            Select Case preliminaryOperatorKind

                Case BinaryOperatorKind.Equals,
                     BinaryOperatorKind.NotEquals,
                     BinaryOperatorKind.LessThanOrEqual,
                     BinaryOperatorKind.GreaterThanOrEqual,
                     BinaryOperatorKind.LessThan,
                     BinaryOperatorKind.GreaterThan,
                     BinaryOperatorKind.Like

                    If OptionCompareText AndAlso (operandType.IsObjectType() OrElse operandType.IsStringType()) Then
                        operatorKind = operatorKind Or BinaryOperatorKind.CompareText
                    End If

                    If Not operatorResultType.IsObjectType() OrElse
                        (isOperandOfConditionalBranch AndAlso preliminaryOperatorKind <> BinaryOperatorKind.Like) Then

                        Dim booleanType As TypeSymbol = GetSpecialTypeForBinaryOperator(node, leftType, rightType, SpecialType.System_Boolean,
                                                              False, diagnostics)

                        If (operatorKind And BinaryOperatorKind.Lifted) <> 0 Then

                            operatorResultType = GetNullableTypeForBinaryOperator(leftType, rightType, booleanType)

                            If (preliminaryOperatorKind = BinaryOperatorKind.Equals OrElse preliminaryOperatorKind = BinaryOperatorKind.NotEquals) AndAlso
                                (IsKnownToBeNullableNothing(left) OrElse IsKnownToBeNullableNothing(right)) Then

                                ReportDiagnostic(diagnostics, node,
                                                 ErrorFactory.ErrorInfo(
                                                     If(preliminaryOperatorKind = BinaryOperatorKind.Equals,
                                                        ERRID.WRN_EqualToLiteralNothing, ERRID.WRN_NotEqualToLiteralNothing)))
                            End If

                            If isOperandOfConditionalBranch Then
                                
                                
                                applyIsTrue = True
                                forceToBooleanType = booleanType
                            End If
                        Else
                            If Not operatorResultType.IsObjectType() Then
                                operatorResultType = booleanType
                            Else
                                
                                Debug.Assert(isOperandOfConditionalBranch AndAlso preliminaryOperatorKind <> BinaryOperatorKind.Like)
                                forceToBooleanType = booleanType
                            End If
                        End If
                    End If
            End Select

            If operandType.GetNullableUnderlyingTypeOrSelf().IsErrorType() OrElse
               operatorResultType.GetNullableUnderlyingTypeOrSelf().IsErrorType() OrElse
               (forceToBooleanType IsNot Nothing AndAlso forceToBooleanType.GetNullableUnderlyingTypeOrSelf().IsErrorType()) Then
                
                If diagnostics Is originalDiagnostics Then
                    diagnostics = New DiagnosticBag()
                End If
            End If

            Dim hasError As Boolean = False

            
            If OptionStrict = VisualBasic.OptionStrict.On Then
                Dim reportedAnEror As Boolean = False

                If leftType.IsObjectType Then
                    ReportBinaryOperatorOnObject(operatorTokenKind, left, preliminaryOperatorKind, diagnostics)
                    reportedAnEror = True
                End If

                If rightType.IsObjectType() Then
                    ReportBinaryOperatorOnObject(operatorTokenKind, right, preliminaryOperatorKind, diagnostics)
                    reportedAnEror = True
                End If

                If reportedAnEror Then
                    hasError = True

                    
                    If diagnostics Is originalDiagnostics Then
                        diagnostics = New DiagnosticBag()
                    End If
                End If
            ElseIf OptionStrict = VisualBasic.OptionStrict.Custom Then 
                If Not isSelectCase OrElse preliminaryOperatorKind <> BinaryOperatorKind.OrElse Then
                    Dim errorId = If(isSelectCase, ERRID.WRN_ObjectMathSelectCase,
                                    If(preliminaryOperatorKind = BinaryOperatorKind.Equals, ERRID.WRN_ObjectMath1,
                                        If(preliminaryOperatorKind = BinaryOperatorKind.NotEquals, ERRID.WRN_ObjectMath1Not, ERRID.WRN_ObjectMath2)))

                    If leftType.IsObjectType Then
                        ReportDiagnostic(diagnostics, left.Syntax, ErrorFactory.ErrorInfo(errorId, operatorTokenKind))
                    End If

                    If rightType.IsObjectType Then
                        ReportDiagnostic(diagnostics, right.Syntax, ErrorFactory.ErrorInfo(errorId, operatorTokenKind))
                    End If
                End If
            End If

            
            Dim explicitSemanticForConcatArgument As Boolean = False

            
            
            
            If preliminaryOperatorKind = BinaryOperatorKind.Concatenate Then
                explicitSemanticForConcatArgument = True

                Debug.Assert((operatorKind And BinaryOperatorKind.Lifted) = 0)

                If operandType.IsStringType() Then
                    If left.Type.IsNullableType Then
                        left = ForceLiftToEmptyString(left, operandType, diagnostics)
                    End If

                    If right.Type.IsNullableType Then
                        right = ForceLiftToEmptyString(right, operandType, diagnostics)
                    End If
                End If
            End If

            Dim beforeConversion As BoundExpression = left
            left = ApplyConversion(left.Syntax, operandType, left, explicitSemanticForConcatArgument, diagnostics,
                                   explicitSemanticForConcatArgument:=explicitSemanticForConcatArgument)

            If explicitSemanticForConcatArgument AndAlso left IsNot beforeConversion AndAlso left.Kind = BoundKind.Conversion Then
                Dim conversion = DirectCast(left, BoundConversion)
                left = conversion.Update(conversion.Operand, conversion.ConversionKind, conversion.Checked, explicitCastInCode:=False,
                                         constantValueOpt:=conversion.ConstantValueOpt, extendedInfoOpt:=conversion.ExtendedInfoOpt,
                                         type:=conversion.Type)
            End If

            If (preliminaryOperatorKind = BinaryOperatorKind.LeftShift OrElse preliminaryOperatorKind = BinaryOperatorKind.RightShift) AndAlso
                Not operandType.IsObjectType() Then

                Dim rightTargetType As TypeSymbol = GetSpecialTypeForBinaryOperator(node, leftType, rightType, SpecialType.System_Int32,
                                                                                False, diagnostics)

                
                

                
                If (operatorKind And BinaryOperatorKind.Lifted) <> 0 Then
                    rightTargetType = GetNullableTypeForBinaryOperator(leftType, rightType, rightTargetType)
                End If

                right = ApplyImplicitConversion(right.Syntax, rightTargetType, right, diagnostics)
            Else
                beforeConversion = right

                right = ApplyConversion(right.Syntax, operandType, right, explicitSemanticForConcatArgument, diagnostics,
                                        explicitSemanticForConcatArgument:=explicitSemanticForConcatArgument)

                If explicitSemanticForConcatArgument AndAlso right IsNot beforeConversion AndAlso right.Kind = BoundKind.Conversion Then
                    Dim conversion = DirectCast(right, BoundConversion)
                    right = conversion.Update(conversion.Operand, conversion.ConversionKind, conversion.Checked, explicitCastInCode:=False,
                                              constantValueOpt:=conversion.ConstantValueOpt, extendedInfoOpt:=conversion.ExtendedInfoOpt,
                                              type:=conversion.Type)
                End If
            End If

            If (operatorKind And BinaryOperatorKind.OpMask) = BinaryOperatorKind.Add AndAlso operatorResultType.IsStringType() Then
                
                operatorKind = (operatorKind And (Not BinaryOperatorKind.OpMask))
                operatorKind = operatorKind Or BinaryOperatorKind.Concatenate
            End If

            
            Dim value As ConstantValue = Nothing

            If Not (left.HasErrors OrElse right.HasErrors) Then
                Dim integerOverflow As Boolean = False
                Dim divideByZero As Boolean = False
                Dim compoundLengthOutOfLimit As Boolean = False

                value = OverloadResolution.TryFoldConstantBinaryOperator(operatorKind,
                                                                         left,
                                                                         right,
                                                                         operatorResultType,
                                                                         integerOverflow,
                                                                         divideByZero,
                                                                         compoundLengthOutOfLimit,
                                                                         compoundStringLength)

                If value IsNot Nothing Then
                    If divideByZero Then
                        Debug.Assert(value.IsBad)
                        ReportDiagnostic(diagnostics, node, ErrorFactory.ErrorInfo(ERRID.ERR_ZeroDivide))
                    ElseIf compoundLengthOutOfLimit Then
                        Debug.Assert(value.IsBad)
                        ReportDiagnostic(diagnostics, node, ErrorFactory.ErrorInfo(ERRID.ERR_ConstantStringTooLong))
                    ElseIf (value.IsBad OrElse integerOverflow) Then
                        
                        ReportDiagnostic(diagnostics, node, ErrorFactory.ErrorInfo(ERRID.ERR_ExpressionOverflow1, operatorResultType))

                        
                        If Not value.IsBad Then
                            value = ConstantValue.Bad
                        End If
                    End If
                End If
            End If

            Dim result As BoundExpression = New BoundBinaryOperator(node, operatorKind, left, right, CheckOverflow, value, operatorResultType, hasError)

            Debug.Assert(Not applyIsTrue OrElse forceToBooleanType IsNot Nothing)

            If forceToBooleanType IsNot Nothing Then
                Debug.Assert(forceToBooleanType.IsBooleanType())

                If applyIsTrue Then
                    Return ApplyNullableIsTrueOperator(result, forceToBooleanType)
                End If

                result = ApplyConversion(node, forceToBooleanType, result, isExplicit:=True, diagnostics:=diagnostics)
            End If

            Return result
        End Function