File: Binding\Binder_Operators.vb
Web Access
Project: src\src\Compilers\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj (Microsoft.CodeAnalysis.VisualBasic)
' Licensed to the .NET Foundation under one or more agreements.
' The .NET Foundation licenses this file to you under the MIT license.
' See the LICENSE file in the project root for more information.
 
Imports System.Collections.Immutable
Imports System.Runtime.InteropServices
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic
 
    ' Binding of binary and unary operators is implemented in this part.
 
    Partial Friend Class Binder
 
        Private Function BindIsExpression(
             node As BinaryExpressionSyntax,
             diagnostics As BindingDiagnosticBag
        ) As BoundExpression
 
            Debug.Assert(node.Kind = SyntaxKind.IsExpression OrElse node.Kind = SyntaxKind.IsNotExpression)
            Dim [isNot] As Boolean = (node.Kind = SyntaxKind.IsNotExpression)
 
            ' The function below will make sure they are RValues.
            Dim left As BoundExpression = BindExpression(node.Left, diagnostics)
            Dim right As BoundExpression = BindExpression(node.Right, diagnostics)
 
            Return BindIsExpression(left, right, node, [isNot], diagnostics)
        End Function
 
        Private Function BindIsExpression(
             left As BoundExpression,
             right As BoundExpression,
             node As SyntaxNode,
             [isNot] As Boolean,
             diagnostics As BindingDiagnosticBag
        ) As BoundExpression
            left = MakeRValue(left, diagnostics)
            right = MakeRValue(right, diagnostics)
 
            ' Suppress Lock conversion warnings for Is operator.
            Dim needsFilterDiagnostics = diagnostics.AccumulatesDiagnostics
            Dim conversionDiagnostics = If(needsFilterDiagnostics, BindingDiagnosticBag.GetInstance(diagnostics), diagnostics)
 
            left = ValidateAndConvertIsExpressionArgument(left, right, [isNot], conversionDiagnostics)
            right = ValidateAndConvertIsExpressionArgument(right, left, [isNot], conversionDiagnostics)
 
            If needsFilterDiagnostics Then
                Debug.Assert(conversionDiagnostics IsNot diagnostics)
                diagnostics.AddDependencies(conversionDiagnostics)
 
                Dim sourceBag = conversionDiagnostics.DiagnosticBag
                Debug.Assert(sourceBag IsNot Nothing)
 
                If Not sourceBag.IsEmptyWithoutResolution Then
                    For Each diagnostic In sourceBag.AsEnumerableWithoutResolution()
                        Dim code As Integer
                        Dim diagnosticWithInfo = TryCast(diagnostic, DiagnosticWithInfo)
                        If diagnosticWithInfo IsNot Nothing AndAlso diagnosticWithInfo.HasLazyInfo Then
                            code = diagnosticWithInfo.LazyInfo.Code
                        Else
                            code = diagnostic.Code
                        End If
 
                        If code <> ERRID.WRN_ConvertingLock Then
                            diagnostics.Add(diagnostic)
                        End If
                    Next
                End If
 
                conversionDiagnostics.Free()
            End If
 
            Dim result As BoundExpression
            Dim booleanType = GetSpecialType(SpecialType.System_Boolean, node, diagnostics)
 
            result = New BoundBinaryOperator(node,
                                             If([isNot], BinaryOperatorKind.IsNot, BinaryOperatorKind.Is),
                                             left,
                                             right,
                                             checked:=False,
                                             type:=booleanType,
                                             hasErrors:=booleanType.IsErrorType())
 
            ' TODO: Add rewrite for Nullable.
 
            Return result
        End Function
 
        ''' <summary>
        ''' Validate and apply appropriate conversion for the target argument of Is/IsNot expression.
        ''' </summary>
        Private Function ValidateAndConvertIsExpressionArgument(
            targetArgument As BoundExpression,
            otherArgument As BoundExpression,
            [isNot] As Boolean,
            diagnostics As BindingDiagnosticBag
        ) As BoundExpression
 
            Dim targetArgumentType As TypeSymbol = targetArgument.Type
            Dim result As BoundExpression
 
            If targetArgument.IsNothingLiteral() Then
                result = targetArgument
 
            ElseIf targetArgumentType.IsErrorType() Then
                result = targetArgument
 
            ElseIf targetArgumentType.IsReferenceType Then
                result = ApplyImplicitConversion(targetArgument.Syntax,
                                                 GetSpecialType(SpecialType.System_Object, targetArgument.Syntax, diagnostics),
                                                 targetArgument,
                                                 diagnostics)
 
            ElseIf targetArgumentType.IsNullableType() Then
                If Not otherArgument.HasErrors AndAlso Not otherArgument.IsNothingLiteral() Then
                    ReportDiagnostic(diagnostics, targetArgument.Syntax,
                                     If([isNot], ERRID.ERR_IsNotOperatorNullable1, ERRID.ERR_IsOperatorNullable1),
                                     targetArgumentType)
                End If
 
                result = targetArgument
 
            ElseIf targetArgumentType.IsTypeParameter() AndAlso Not targetArgumentType.IsValueType Then
                If Not otherArgument.HasErrors AndAlso Not otherArgument.IsNothingLiteral() Then
                    ReportDiagnostic(diagnostics, targetArgument.Syntax,
                                     If([isNot], ERRID.ERR_IsNotOperatorGenericParam1, ERRID.ERR_IsOperatorGenericParam1),
                                     targetArgumentType)
                End If
 
                ' If any of the left or right operands of the Is or IsNot operands
                ' are entities of type parameters types, then they need to be boxed.
                result = ApplyImplicitConversion(targetArgument.Syntax,
                                                 GetSpecialType(SpecialType.System_Object, targetArgument.Syntax, diagnostics),
                                                 targetArgument,
                                                 diagnostics)
 
            Else
                ReportDiagnostic(diagnostics, targetArgument.Syntax,
                                 If([isNot], ERRID.ERR_IsNotOpRequiresReferenceTypes1, ERRID.ERR_IsOperatorRequiresReferenceTypes1),
                                 targetArgumentType)
 
                result = targetArgument
            End If
 
            Return result
        End Function
 
        Private Function BindBinaryOperator(
            node As BinaryExpressionSyntax,
            isOperandOfConditionalBranch As Boolean,
            diagnostics As BindingDiagnosticBag
        ) As BoundExpression
            ' Some tools, such as ASP .NET, generate expressions containing thousands
            ' of string concatenations. For this reason, for string concatenations,
            ' avoid the usual recursion along the left side of the parse. Also, attempt
            ' to flatten whole sequences of string literal concatenations to avoid
            ' allocating space for intermediate results.
 
            Dim preliminaryOperatorKind As BinaryOperatorKind = OverloadResolution.MapBinaryOperatorKind(node.Kind)
            Dim propagateIsOperandOfConditionalBranch = isOperandOfConditionalBranch AndAlso
                                                            (preliminaryOperatorKind = BinaryOperatorKind.AndAlso OrElse
                                                                preliminaryOperatorKind = BinaryOperatorKind.OrElse)
 
            Dim binary As BinaryExpressionSyntax = node
            Dim child As ExpressionSyntax
 
            Do
                child = binary.Left
 
                Select Case child.Kind
                    Case SyntaxKind.AddExpression,
                         SyntaxKind.ConcatenateExpression,
                         SyntaxKind.LikeExpression,
                         SyntaxKind.EqualsExpression,
                         SyntaxKind.NotEqualsExpression,
                         SyntaxKind.LessThanOrEqualExpression,
                         SyntaxKind.GreaterThanOrEqualExpression,
                         SyntaxKind.LessThanExpression,
                         SyntaxKind.GreaterThanExpression,
                         SyntaxKind.SubtractExpression,
                         SyntaxKind.MultiplyExpression,
                         SyntaxKind.ExponentiateExpression,
                         SyntaxKind.DivideExpression,
                         SyntaxKind.ModuloExpression,
                         SyntaxKind.IntegerDivideExpression,
                         SyntaxKind.LeftShiftExpression,
                         SyntaxKind.RightShiftExpression,
                         SyntaxKind.ExclusiveOrExpression,
                         SyntaxKind.OrExpression,
                         SyntaxKind.AndExpression
 
                        If propagateIsOperandOfConditionalBranch Then
                            Exit Do
                        End If
 
                    Case SyntaxKind.OrElseExpression,
                         SyntaxKind.AndAlsoExpression
                        Exit Select
 
                    Case Else
                        Exit Do
                End Select
 
                binary = DirectCast(child, BinaryExpressionSyntax)
            Loop
 
            Dim left As BoundExpression = BindValue(child, diagnostics, propagateIsOperandOfConditionalBranch)
 
            Do
                binary = DirectCast(child.Parent, BinaryExpressionSyntax)
 
                Dim right As BoundExpression = BindValue(binary.Right, diagnostics, propagateIsOperandOfConditionalBranch)
 
                left = BindBinaryOperator(binary, left, right, binary.OperatorToken.Kind,
                                          OverloadResolution.MapBinaryOperatorKind(binary.Kind),
                                          If(binary Is node, isOperandOfConditionalBranch, propagateIsOperandOfConditionalBranch),
                                          diagnostics)
 
                child = binary
            Loop While child IsNot node
 
            Return left
        End Function
 
        Private Function BindBinaryOperator(
            node As SyntaxNode,
            left As BoundExpression,
            right As BoundExpression,
            operatorTokenKind As SyntaxKind,
            preliminaryOperatorKind As BinaryOperatorKind,
            isOperandOfConditionalBranch As Boolean,
            diagnostics As BindingDiagnosticBag,
            Optional isSelectCase As Boolean = False
        ) As BoundExpression
 
            Debug.Assert(left.IsValue)
            Debug.Assert(right.IsValue)
 
            Dim originalDiagnostics = diagnostics
 
            If (left.HasErrors OrElse right.HasErrors) Then
                ' Suppress any additional diagnostics by overriding DiagnosticBag.
                diagnostics = BindingDiagnosticBag.Discarded
            End If
 
            ' Deal with NOTHING literal as an input.
            ConvertNothingLiterals(preliminaryOperatorKind, left, right, diagnostics)
 
            left = MakeRValue(left, diagnostics)
            right = MakeRValue(right, diagnostics)
 
            If (left.HasErrors OrElse right.HasErrors) Then
                ' Suppress any additional diagnostics by overriding DiagnosticBag.
                If diagnostics Is originalDiagnostics Then
                    diagnostics = BindingDiagnosticBag.Discarded
                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()
 
            '§11.16 Concatenation Operator
            'A System.DBNull value is converted to the literal Nothing typed as String. 
            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
 
            ' For comparison operators, the result type computed here is not
            ' the result type of the comparison (which is typically boolean),
            ' but is the type to which the operands are to be converted. For
            ' other operators, the type computed here is both the result type
            ' and the common operand type.
            Dim intrinsicOperatorType As SpecialType = SpecialType.None
            Dim userDefinedOperator As OverloadResolution.OverloadResolutionResult = Nothing
            Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics)
            Dim operatorKind As BinaryOperatorKind = OverloadResolution.ResolveBinaryOperator(preliminaryOperatorKind, left, right, Me,
                                                                                              True,
                                                                                              intrinsicOperatorType,
                                                                                              userDefinedOperator,
                                                                                              useSiteInfo)
 
            If diagnostics.Add(node, useSiteInfo) Then
                ' Suppress additional diagnostics
                diagnostics = BindingDiagnosticBag.Discarded
            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
 
            ' We are dealing with intrinsic operator 
 
            ' Get the symbol for operand type
            Dim operandType As TypeSymbol
 
            If intrinsicOperatorType = SpecialType.None Then
                ' Must be a bitwise operation with enum type.
                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
 
            ' Get the symbol for result type
            Dim operatorResultType As TypeSymbol = operandType
 
            Dim forceToBooleanType As TypeSymbol = Nothing
 
            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
                        Else
                            If Not operatorResultType.IsObjectType() Then
                                operatorResultType = booleanType
                            Else
                                ' I believe this is just an optimization to prevent Object from bubbling up the tree.
                                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
                ' Suppress any additional diagnostics by overriding DiagnosticBag.
                If diagnostics Is originalDiagnostics Then
                    diagnostics = BindingDiagnosticBag.Discarded
                End If
            End If
 
            Dim hasError As Boolean = False
 
            ' Option Strict disallows all operations on Object operands. Or, at least, warn.
            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
 
                    ' Suppress any additional diagnostics by overriding DiagnosticBag.
                    If diagnostics Is originalDiagnostics Then
                        diagnostics = BindingDiagnosticBag.Discarded
                    End If
                End If
            ElseIf OptionStrict = VisualBasic.OptionStrict.Custom Then 'warn if option strict is off
                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
 
            ' Apply conversions to operands.
            Dim explicitSemanticForConcatArgument As Boolean = False
 
            ' Concatenation will apply conversions to its operands as if the
            ' conversions were explicit. Effectively, the use of the concatenation
            ' operator is treated as an explicit conversion to String.
            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)
 
                '§11.18 Shift Operators
                'The type of the right operand must be implicitly convertible to Integer 
 
                ' If operator is lifted, convert right operand to Nullable(Of Integer)
                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
                ' Transform the addition into a string concatenation.  This won't use a runtime helper - it will turn into System.String::Concat
                operatorKind = (operatorKind And (Not BinaryOperatorKind.OpMask))
                operatorKind = operatorKind Or BinaryOperatorKind.Concatenate
            End If
 
            ' Perform constant folding.
            Dim value As ConstantValue = Nothing
 
            If Not (left.HasErrors OrElse right.HasErrors) Then
                Dim integerOverflow As Boolean = False
                Dim divideByZero As Boolean = False
                Dim lengthOutOfLimit As Boolean = False
 
                value = OverloadResolution.TryFoldConstantBinaryOperator(operatorKind,
                                                                         left,
                                                                         right,
                                                                         operatorResultType,
                                                                         integerOverflow,
                                                                         divideByZero,
                                                                         lengthOutOfLimit)
 
                If value IsNot Nothing Then
                    If divideByZero Then
                        Debug.Assert(value.IsBad)
                        ReportDiagnostic(diagnostics, node, ErrorFactory.ErrorInfo(ERRID.ERR_ZeroDivide))
                    ElseIf lengthOutOfLimit Then
                        Debug.Assert(value.IsBad)
                        ReportDiagnostic(diagnostics, right.Syntax, ErrorFactory.ErrorInfo(ERRID.ERR_ConstantStringTooLong))
                    ElseIf (value.IsBad OrElse integerOverflow) Then
                        ' Overflows are reported regardless of the value of OptionRemoveIntegerOverflowChecks, Dev10 behavior.
                        ReportDiagnostic(diagnostics, node, ErrorFactory.ErrorInfo(ERRID.ERR_ExpressionOverflow1, operatorResultType))
 
                        ' there should be no constant value in case of overflows.
                        If Not value.IsBad Then
                            value = ConstantValue.Bad
                        End If
                    End If
                End If
            End If
 
            Dim result As BoundExpression = New BoundBinaryOperator(node, operatorKind Or If(isOperandOfConditionalBranch, BinaryOperatorKind.IsOperandOfConditionalBranch, Nothing),
                                                                    left, right, CheckOverflow, value, operatorResultType, hasError)
 
            If forceToBooleanType IsNot Nothing Then
                Debug.Assert(forceToBooleanType.IsBooleanType())
 
                result = ApplyConversion(node, forceToBooleanType, result, isExplicit:=True, diagnostics:=diagnostics)
            End If
 
            Return result
        End Function
 
        ''' <summary>
        ''' This helper is used to wrap nullable argument into something that would return null string if argument is null.
        '''
        ''' Unlike conversion to a string where nullable nulls result in an exception,         
        ''' concatenation requires that nullable nulls are treated as null strings. 
        ''' Note that conversion is treated as explicit conversion.
        ''' </summary>
        Private Function ForceLiftToEmptyString(left As BoundExpression, stringType As TypeSymbol, diagnostics As BindingDiagnosticBag) As BoundExpression
            Debug.Assert(stringType.IsStringType)
 
            Dim nothingStr = New BoundLiteral(left.Syntax, ConstantValue.Nothing, stringType).MakeCompilerGenerated()
 
            Return AnalyzeConversionAndCreateBinaryConditionalExpression(left.Syntax,
                                                                         left,
                                                                         nothingStr,
                                                                         Nothing,
                                                                         stringType,
                                                                         False,
                                                                         diagnostics,
                                                                         explicitConversion:=True).MakeCompilerGenerated()
        End Function
 
        Private Function BindUserDefinedNonShortCircuitingBinaryOperator(
            node As SyntaxNode,
            opKind As BinaryOperatorKind,
            left As BoundExpression,
            right As BoundExpression,
            <[In]> ByRef userDefinedOperator As OverloadResolution.OverloadResolutionResult,
            diagnostics As BindingDiagnosticBag
        ) As BoundUserDefinedBinaryOperator
            Debug.Assert(userDefinedOperator.Candidates.Length > 0)
 
            opKind = opKind Or BinaryOperatorKind.UserDefined
 
            Dim result As BoundExpression
 
            If userDefinedOperator.BestResult.HasValue Then
                Dim bestCandidate As OverloadResolution.CandidateAnalysisResult = userDefinedOperator.BestResult.Value
 
                result = CreateBoundCallOrPropertyAccess(node, node, TypeCharacter.None,
                                                         New BoundMethodGroup(node, Nothing,
                                                                              ImmutableArray.Create(Of MethodSymbol)(
                                                                                  DirectCast(bestCandidate.Candidate.UnderlyingSymbol, MethodSymbol)),
                                                                              LookupResultKind.Good, Nothing,
                                                                              QualificationKind.Unqualified).MakeCompilerGenerated(),
                                                         ImmutableArray.Create(Of BoundExpression)(left, right),
                                                         bestCandidate,
                                                         userDefinedOperator.AsyncLambdaSubToFunctionMismatch,
                                                         diagnostics)
 
                If bestCandidate.Candidate.IsLifted Then
                    opKind = opKind Or BinaryOperatorKind.Lifted
                End If
            Else
                result = ReportOverloadResolutionFailureAndProduceBoundNode(node, LookupResultKind.Good,
                                                                            ImmutableArray.Create(Of BoundExpression)(left, right),
                                                                            Nothing, userDefinedOperator, diagnostics,
                                                                            callerInfoOpt:=Nothing)
            End If
 
            Return New BoundUserDefinedBinaryOperator(node, opKind, result, CheckOverflow, result.Type)
        End Function
 
        ''' <summary>
        ''' This function builds a bound tree representing an overloaded short circuiting expression
        ''' after determining that the necessary semantic conditions are met.
        ''' 
        ''' An expression of the form:
        ''' 
        '''     x AndAlso y  (where the type of x is X and the type of y is Y)
        ''' 
        ''' is an overloaded short circuit operation if X and Y are user-defined types and an
        ''' applicable operator And exists after applying normal operator resolution rules.
        ''' 
        ''' Given an applicable And operator declared in type T, the following must be true:
        ''' 
        '''     - The return type and parameter types must be T.
        '''     - T must contain a declaration of operator IsFalse.
        ''' 
        ''' If these conditions are met, the expression "x AndAlso y" is translated into:
        ''' 
        '''     !T.IsFalse(temp = x) ? T.And(temp, y) : temp
        ''' 
        ''' The temporary is necessary for evaluating x only once. Similarly, "x OrElse y" is
        ''' translated into:
        ''' 
        '''     !T.IsTrue(temp = x) ? T.Or(temp, y) : temp
        ''' </summary>
        Private Function BindUserDefinedShortCircuitingOperator(
            node As SyntaxNode,
            opKind As BinaryOperatorKind,
            left As BoundExpression,
            right As BoundExpression,
            <[In]> ByRef bitwiseOperator As OverloadResolution.OverloadResolutionResult,
            diagnostics As BindingDiagnosticBag
        ) As BoundUserDefinedShortCircuitingOperator
            Debug.Assert(opKind = BinaryOperatorKind.AndAlso OrElse opKind = BinaryOperatorKind.OrElse)
            Debug.Assert(bitwiseOperator.Candidates.Length > 0)
 
            Dim bitwiseKind As BinaryOperatorKind = If(opKind = BinaryOperatorKind.AndAlso, BinaryOperatorKind.And, BinaryOperatorKind.Or) Or BinaryOperatorKind.UserDefined
 
            Dim operatorType As TypeSymbol
            Dim leftOperand As BoundExpression = Nothing
            Dim leftPlaceholder As BoundRValuePlaceholder = Nothing
            Dim test As BoundExpression = Nothing
            Dim bitwise As BoundUserDefinedBinaryOperator
            Dim hasErrors As Boolean = False
 
            If Not bitwiseOperator.BestResult.HasValue Then
                ' This will take care of the diagnostic.
                bitwise = BindUserDefinedNonShortCircuitingBinaryOperator(node, bitwiseKind, left, right, bitwiseOperator, diagnostics)
                operatorType = bitwise.Type
                hasErrors = True
                GoTo Done
            End If
 
            Dim bitwiseAnalysis As OverloadResolution.CandidateAnalysisResult = bitwiseOperator.BestResult.Value
            Dim bitwiseCandidate As OverloadResolution.Candidate = bitwiseAnalysis.Candidate
            operatorType = bitwiseCandidate.ReturnType
 
            If bitwiseCandidate.IsLifted Then
                bitwiseKind = bitwiseKind Or BinaryOperatorKind.Lifted
            End If
 
            If Not operatorType.IsSameTypeIgnoringAll(bitwiseCandidate.Parameters(0).Type) OrElse
               Not operatorType.IsSameTypeIgnoringAll(bitwiseCandidate.Parameters(1).Type) Then
                ReportDiagnostic(diagnostics, node, ERRID.ERR_UnacceptableLogicalOperator3,
                                 bitwiseCandidate.UnderlyingSymbol,
                                 bitwiseCandidate.UnderlyingSymbol.ContainingType,
                                 SyntaxFacts.GetText(If(opKind = BinaryOperatorKind.AndAlso,
                                                        SyntaxKind.AndAlsoKeyword, SyntaxKind.OrElseKeyword)))
 
                bitwise = BindUserDefinedNonShortCircuitingBinaryOperator(node, bitwiseKind, left, right, bitwiseOperator,
                                                                          BindingDiagnosticBag.Discarded) ' Ignore any additional diagnostics.
                hasErrors = True
                GoTo Done
            End If
 
            leftPlaceholder = New BoundRValuePlaceholder(left.Syntax, operatorType).MakeCompilerGenerated()
 
            ' Find IsTrue/IsFalse operator
            Dim leftCheckOperator As OverloadResolution.OverloadResolutionResult
 
            Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics)
 
            If opKind = BinaryOperatorKind.AndAlso Then
                leftCheckOperator = OverloadResolution.ResolveIsFalseOperator(leftPlaceholder, Me, useSiteInfo)
            Else
                leftCheckOperator = OverloadResolution.ResolveIsTrueOperator(leftPlaceholder, Me, useSiteInfo)
            End If
 
            If diagnostics.Add(node, useSiteInfo) Then
                ' Suppress additional diagnostics
                diagnostics = BindingDiagnosticBag.Discarded
            End If
 
            If Not leftCheckOperator.BestResult.HasValue Then
                ReportDiagnostic(diagnostics, node, ERRID.ERR_ConditionOperatorRequired3,
                                 operatorType,
                                 SyntaxFacts.GetText(If(opKind = BinaryOperatorKind.AndAlso, SyntaxKind.IsFalseKeyword, SyntaxKind.IsTrueKeyword)),
                                 SyntaxFacts.GetText(If(opKind = BinaryOperatorKind.AndAlso, SyntaxKind.AndAlsoKeyword, SyntaxKind.OrElseKeyword)))
 
                bitwise = BindUserDefinedNonShortCircuitingBinaryOperator(node, bitwiseKind, left, right, bitwiseOperator,
                                                                          BindingDiagnosticBag.Discarded) ' Ignore any additional diagnostics.
                leftPlaceholder = Nothing
                hasErrors = True
                GoTo Done
            End If
 
            Dim checkCandidate As OverloadResolution.Candidate = leftCheckOperator.BestResult.Value.Candidate
            Debug.Assert(checkCandidate.ReturnType.IsBooleanType() OrElse checkCandidate.ReturnType.IsNullableOfBoolean())
 
            If Not operatorType.IsSameTypeIgnoringAll(checkCandidate.Parameters(0).Type) Then
                ReportDiagnostic(diagnostics, node, ERRID.ERR_BinaryOperands3,
                                 SyntaxFacts.GetText(If(opKind = BinaryOperatorKind.AndAlso, SyntaxKind.AndAlsoKeyword, SyntaxKind.OrElseKeyword)),
                                 left.Type, right.Type)
 
                hasErrors = True
                diagnostics = BindingDiagnosticBag.Discarded ' Ignore any additional diagnostics.
                bitwise = BindUserDefinedNonShortCircuitingBinaryOperator(node, bitwiseKind, left, right, bitwiseOperator, diagnostics)
            Else
                ' Convert the operands to the operator type.
                Dim argumentInfo As (Arguments As ImmutableArray(Of BoundExpression), DefaultArguments As BitVector) =
                    PassArguments(node, bitwiseAnalysis, ImmutableArray.Create(Of BoundExpression)(left, right), diagnostics)
                Debug.Assert(argumentInfo.DefaultArguments.IsNull)
                bitwiseAnalysis.ConversionsOpt = Nothing
 
                bitwise = New BoundUserDefinedBinaryOperator(node, bitwiseKind,
                                                             CreateBoundCallOrPropertyAccess(node, node, TypeCharacter.None,
                                                                 New BoundMethodGroup(node, Nothing,
                                                                                      ImmutableArray.Create(Of MethodSymbol)(
                                                                                          DirectCast(bitwiseCandidate.UnderlyingSymbol, MethodSymbol)),
                                                                                      LookupResultKind.Good, Nothing,
                                                                                      QualificationKind.Unqualified).MakeCompilerGenerated(),
                                                                 ImmutableArray.Create(Of BoundExpression)(leftPlaceholder, argumentInfo.Arguments(1)),
                                                                 bitwiseAnalysis,
                                                                 bitwiseOperator.AsyncLambdaSubToFunctionMismatch,
                                                                 diagnostics),
                                                             CheckOverflow,
                                                             operatorType)
 
                leftOperand = argumentInfo.Arguments(0)
            End If
 
            Dim testOp As BoundUserDefinedUnaryOperator = BindUserDefinedUnaryOperator(node,
                                                                                       If(opKind = BinaryOperatorKind.AndAlso,
                                                                                          UnaryOperatorKind.IsFalse,
                                                                                          UnaryOperatorKind.IsTrue),
                                                                                       leftPlaceholder,
                                                                                       leftCheckOperator,
                                                                                       diagnostics).MakeCompilerGenerated()
            testOp.UnderlyingExpression.SetWasCompilerGenerated()
 
            If hasErrors Then
                leftPlaceholder = Nothing
            End If
 
            If checkCandidate.IsLifted Then
                test = ApplyNullableIsTrueOperator(testOp, checkCandidate.ReturnType.GetNullableUnderlyingTypeOrSelf())
            Else
                test = testOp
            End If
 
Done:
            Debug.Assert(hasErrors OrElse (leftOperand IsNot Nothing AndAlso leftPlaceholder IsNot Nothing AndAlso test IsNot Nothing))
            Debug.Assert(Not hasErrors OrElse (leftOperand Is Nothing AndAlso leftPlaceholder Is Nothing))
 
            bitwise.UnderlyingExpression.SetWasCompilerGenerated()
            bitwise.SetWasCompilerGenerated()
            Return New BoundUserDefinedShortCircuitingOperator(node, leftOperand, leftPlaceholder, test, bitwise, operatorType, hasErrors)
        End Function
 
        Private Shared Sub ReportBinaryOperatorOnObject(
            operatorTokenKind As SyntaxKind,
            operand As BoundExpression,
            preliminaryOperatorKind As BinaryOperatorKind,
            diagnostics As BindingDiagnosticBag
        )
            ReportDiagnostic(diagnostics, operand.Syntax,
                             ErrorFactory.ErrorInfo(
                                 If(preliminaryOperatorKind = BinaryOperatorKind.Equals OrElse preliminaryOperatorKind = BinaryOperatorKind.NotEquals,
                                    ERRID.ERR_StrictDisallowsObjectComparison1, ERRID.ERR_StrictDisallowsObjectOperand1),
                                 operatorTokenKind))
        End Sub
 
        ''' <summary>
        ''' Returns Symbol for String type.
        ''' </summary>
        Private Function SubstituteDBNullWithNothingString(
            ByRef dbNullOperand As BoundExpression,
            otherOperandType As TypeSymbol,
            diagnostics As BindingDiagnosticBag
        ) As TypeSymbol
            Dim stringType As TypeSymbol
 
            If otherOperandType.IsStringType() Then
                stringType = otherOperandType
            Else
                stringType = GetSpecialType(SpecialType.System_String, dbNullOperand.Syntax, diagnostics)
            End If
 
            dbNullOperand = New BoundConversion(dbNullOperand.Syntax, dbNullOperand, ConversionKind.Widening,
                                        checked:=False, explicitCastInCode:=False, type:=stringType,
                                        constantValueOpt:=ConstantValue.Nothing)
 
            Return stringType
        End Function
 
        ''' <summary>
        ''' Get symbol for a special type, reuse symbols for operand types to avoid type 
        ''' lookups and construction of new instances of symbols.
        ''' </summary>
        Private Function GetSpecialTypeForBinaryOperator(
            node As SyntaxNode,
            leftType As TypeSymbol,
            rightType As TypeSymbol,
            specialType As SpecialType,
            makeNullable As Boolean,
            diagnostics As BindingDiagnosticBag
        ) As TypeSymbol
            Debug.Assert(specialType <> Microsoft.CodeAnalysis.SpecialType.None)
            Debug.Assert(Not makeNullable OrElse leftType.IsNullableType() OrElse rightType.IsNullableType())
 
            Dim resultType As TypeSymbol
            Dim leftNullableUnderlying = leftType.GetNullableUnderlyingTypeOrSelf()
            Dim leftSpecialType = leftNullableUnderlying.SpecialType
            Dim rightNullableUnderlying = rightType.GetNullableUnderlyingTypeOrSelf()
            Dim rightSpecialType = rightNullableUnderlying.SpecialType
 
            If leftSpecialType = specialType Then
 
                If Not makeNullable Then
                    resultType = leftNullableUnderlying
                ElseIf leftType.IsNullableType() Then
                    resultType = leftType
                ElseIf rightSpecialType = specialType Then
                    Debug.Assert(makeNullable AndAlso rightType.IsNullableType())
                    resultType = rightType
                Else
                    Debug.Assert(makeNullable AndAlso
                                 rightType.IsNullableType() AndAlso
                                 Not leftType.IsNullableType())
                    resultType = DirectCast(rightType.OriginalDefinition, NamedTypeSymbol).Construct(leftType)
                End If
 
            ElseIf rightSpecialType = specialType Then
 
                If Not makeNullable Then
                    resultType = rightNullableUnderlying
                ElseIf rightType.IsNullableType() Then
                    resultType = rightType
                Else
                    Debug.Assert(makeNullable AndAlso
                                 Not rightType.IsNullableType() AndAlso
                                 leftType.IsNullableType())
 
                    resultType = DirectCast(leftType.OriginalDefinition, NamedTypeSymbol).Construct(rightNullableUnderlying)
                End If
            Else
                resultType = GetSpecialType(specialType, node, diagnostics)
 
                If makeNullable Then
                    If leftType.IsNullableType() Then
                        resultType = DirectCast(leftType.OriginalDefinition, NamedTypeSymbol).Construct(resultType)
                    Else
                        Debug.Assert(rightType.IsNullableType())
                        resultType = DirectCast(rightType.OriginalDefinition, NamedTypeSymbol).Construct(resultType)
                    End If
                End If
            End If
 
            Return resultType
        End Function
 
        ''' <summary>
        ''' Get symbol for a Nullable type of particular type, reuse symbols for operand types to avoid type 
        ''' lookups and construction of new instances of symbols.
        ''' </summary>
        Private Shared Function GetNullableTypeForBinaryOperator(
            leftType As TypeSymbol,
            rightType As TypeSymbol,
            ofType As TypeSymbol
        ) As TypeSymbol
            Dim leftIsNullable = leftType.IsNullableType()
            Dim rightIsNullable = rightType.IsNullableType()
            Dim ofSpecialType = ofType.SpecialType
 
            Debug.Assert(leftIsNullable OrElse rightIsNullable)
 
            If ofSpecialType <> SpecialType.None Then
                If leftIsNullable AndAlso leftType.GetNullableUnderlyingType().SpecialType = ofSpecialType Then
                    Return leftType
                ElseIf rightIsNullable AndAlso rightType.GetNullableUnderlyingType().SpecialType = ofSpecialType Then
                    Return rightType
                End If
            End If
 
            If leftIsNullable Then
                Return DirectCast(leftType.OriginalDefinition, NamedTypeSymbol).Construct(ofType)
            Else
                Return DirectCast(rightType.OriginalDefinition, NamedTypeSymbol).Construct(ofType)
            End If
        End Function
 
        Private Shared Function IsKnownToBeNullableNothing(expr As BoundExpression) As Boolean
            Dim cast = expr
 
            ' TODO: Add handling for TryCast, similar to DirectCast
            While cast.Kind = BoundKind.Conversion OrElse cast.Kind = BoundKind.DirectCast
 
                If cast.HasErrors Then
                    Return False
                End If
 
                Dim resultType As TypeSymbol = Nothing
 
                Select Case cast.Kind
                    Case BoundKind.Conversion
                        Dim conv = DirectCast(cast, BoundConversion)
                        resultType = conv.Type
                        cast = conv.Operand
 
                    Case BoundKind.DirectCast
                        Dim conv = DirectCast(cast, BoundDirectCast)
                        resultType = conv.Type
                        cast = conv.Operand
                End Select
 
                If resultType Is Nothing OrElse Not (resultType.IsNullableType() OrElse resultType.IsObjectType()) Then
                    Return False
                End If
            End While
 
            Return cast.IsNothingLiteral()
        End Function
 
        Private Sub ReportUndefinedOperatorError(
            syntax As SyntaxNode,
            left As BoundExpression,
            right As BoundExpression,
            operatorTokenKind As SyntaxKind,
            operatorKind As BinaryOperatorKind,
            diagnostics As BindingDiagnosticBag
        )
            Dim leftType = left.Type
            Dim rightType = right.Type
 
            Debug.Assert(leftType IsNot Nothing)
            Debug.Assert(rightType IsNot Nothing)
 
            If leftType.IsErrorType() OrElse rightType.IsErrorType() Then
                Return ' Let's not report more errors.
            End If
 
            Dim operatorTokenText = SyntaxFacts.GetText(operatorTokenKind)
 
            If OverloadResolution.UseUserDefinedBinaryOperators(operatorKind, leftType, rightType) AndAlso
                Not leftType.CanContainUserDefinedOperators(useSiteInfo:=CompoundUseSiteInfo(Of AssemblySymbol).Discarded) AndAlso Not rightType.CanContainUserDefinedOperators(useSiteInfo:=CompoundUseSiteInfo(Of AssemblySymbol).Discarded) AndAlso
                (operatorKind = BinaryOperatorKind.Equals OrElse operatorKind = BinaryOperatorKind.NotEquals) AndAlso
                leftType.IsReferenceType() AndAlso rightType.IsReferenceType() Then
                ReportDiagnostic(diagnostics, syntax, ERRID.ERR_ReferenceComparison3, operatorTokenText, leftType, rightType)
 
            ElseIf IsIEnumerableOfXElement(leftType, CompoundUseSiteInfo(Of AssemblySymbol).Discarded) Then
                ReportDiagnostic(diagnostics, syntax, ERRID.ERR_BinaryOperandsForXml4, operatorTokenText, leftType, rightType, leftType)
 
            ElseIf IsIEnumerableOfXElement(rightType, CompoundUseSiteInfo(Of AssemblySymbol).Discarded) Then
                ReportDiagnostic(diagnostics, syntax, ERRID.ERR_BinaryOperandsForXml4, operatorTokenText, leftType, rightType, rightType)
 
            Else
                ReportDiagnostic(diagnostics, syntax, ERRID.ERR_BinaryOperands3, operatorTokenText, leftType, rightType)
 
            End If
        End Sub
 
        ''' <summary>
        ''' §11.12.2 Object Operands
        ''' The value Nothing is treated as the default value of the type of 
        ''' the other operand in a binary operator expression. In a unary operator expression, 
        ''' or if both operands are Nothing in a binary operator expression, 
        ''' the type of the operation is Integer or the only result type of the operator, 
        ''' if the operator does not result in Integer.
        ''' </summary>
        Private Sub ConvertNothingLiterals(
            operatorKind As BinaryOperatorKind,
            ByRef left As BoundExpression,
            ByRef right As BoundExpression,
            diagnostics As BindingDiagnosticBag
        )
            Debug.Assert((operatorKind And BinaryOperatorKind.OpMask) = operatorKind AndAlso operatorKind <> 0)
 
            Dim rightType As TypeSymbol
            Dim leftType As TypeSymbol
 
            If left.IsNothingLiteral() Then
 
                If right.IsNothingLiteral() Then
                    ' Both are NOTHING
                    Dim defaultRightSpecialType As SpecialType
 
                    Select Case operatorKind
                        Case BinaryOperatorKind.Concatenate,
                             BinaryOperatorKind.Like
                            defaultRightSpecialType = SpecialType.System_String
 
                        Case BinaryOperatorKind.OrElse,
                             BinaryOperatorKind.AndAlso
                            defaultRightSpecialType = SpecialType.System_Boolean
 
                        Case BinaryOperatorKind.Add,
                             BinaryOperatorKind.Equals,
                             BinaryOperatorKind.NotEquals,
                             BinaryOperatorKind.LessThanOrEqual,
                             BinaryOperatorKind.GreaterThanOrEqual,
                             BinaryOperatorKind.LessThan,
                             BinaryOperatorKind.GreaterThan,
                             BinaryOperatorKind.Subtract,
                             BinaryOperatorKind.Multiply,
                             BinaryOperatorKind.Power,
                             BinaryOperatorKind.Divide,
                             BinaryOperatorKind.Modulo,
                             BinaryOperatorKind.IntegerDivide,
                             BinaryOperatorKind.LeftShift,
                             BinaryOperatorKind.RightShift,
                             BinaryOperatorKind.Xor,
                             BinaryOperatorKind.Or,
                             BinaryOperatorKind.And
                            defaultRightSpecialType = SpecialType.System_Int32
 
                        Case Else
                            Throw ExceptionUtilities.UnexpectedValue(operatorKind)
                    End Select
 
                    rightType = GetSpecialType(defaultRightSpecialType, right.Syntax, diagnostics)
                    right = ApplyImplicitConversion(right.Syntax,
                                                    rightType,
                                                    right, diagnostics)
                Else
                    rightType = right.Type
 
                    If rightType Is Nothing Then
                        Return
                    End If
                End If
 
                Debug.Assert(rightType IsNot Nothing)
                Dim defaultLeftSpecialType As SpecialType = SpecialType.None
 
                Select Case operatorKind
                    Case BinaryOperatorKind.Concatenate,
                         BinaryOperatorKind.Like
 
                        If rightType.GetNullableUnderlyingTypeOrSelf().GetEnumUnderlyingTypeOrSelf().IsIntrinsicType() OrElse
                           rightType.IsCharSZArray() OrElse
                           rightType.IsDBNullType() Then
 
                            ' For & and Like, a Nothing operand is typed String unless the other operand
                            ' is non-intrinsic (VSW#240203).
                            ' The same goes for DBNull (VSW#278518)
                            ' The same goes for enum types (VSW#288077)
                            defaultLeftSpecialType = SpecialType.System_String
                        End If
 
                    Case BinaryOperatorKind.LeftShift,
                         BinaryOperatorKind.RightShift
                        ' Nothing should default to Integer for Shift operations.
                        defaultLeftSpecialType = SpecialType.System_Int32
                End Select
 
                If defaultLeftSpecialType = SpecialType.None OrElse defaultLeftSpecialType = rightType.SpecialType Then
                    leftType = rightType
                Else
                    leftType = GetSpecialType(defaultLeftSpecialType, left.Syntax, diagnostics)
                End If
 
                left = ApplyImplicitConversion(left.Syntax,
                                                leftType,
                                                left, diagnostics)
 
            ElseIf right.IsNothingLiteral() Then
 
                leftType = left.Type
                If leftType Is Nothing Then
                    Return
                End If
 
                rightType = leftType
 
                Select Case operatorKind
                    Case BinaryOperatorKind.Concatenate,
                         BinaryOperatorKind.Like
 
                        If leftType.GetNullableUnderlyingTypeOrSelf().GetEnumUnderlyingTypeOrSelf().IsIntrinsicType() OrElse
                           leftType.IsCharSZArray() OrElse
                           leftType.IsDBNullType() Then
 
                            ' For & and Like, a Nothing operand is typed String unless the other operand
                            ' is non-intrinsic (VSW#240203).
                            ' The same goes for DBNull (VSW#278518)
                            ' The same goes for enum types (VSW#288077)
                            If leftType.SpecialType <> SpecialType.System_String Then
                                rightType = GetSpecialType(SpecialType.System_String, right.Syntax, diagnostics)
                            End If
                        End If
                End Select
 
                right = ApplyImplicitConversion(right.Syntax,
                                                rightType,
                                                right, diagnostics)
            End If
        End Sub
 
        Private Function BindUnaryOperator(node As UnaryExpressionSyntax, diagnostics As BindingDiagnosticBag) As BoundExpression
 
            Dim operand As BoundExpression = BindValue(node.Operand, diagnostics)
            Dim preliminaryOperatorKind As UnaryOperatorKind = OverloadResolution.MapUnaryOperatorKind(node.Kind)
 
            If Not operand.HasErrors AndAlso operand.IsNothingLiteral Then
                '§11.12.2 Object Operands
                'In a unary operator expression, or if both operands are Nothing in a 
                'binary operator expression, the type of the operation is Integer
                Dim int32Type = GetSpecialType(SpecialType.System_Int32, node.Operand, diagnostics)
                operand = ApplyImplicitConversion(node.Operand, int32Type, operand, diagnostics)
            Else
                operand = MakeRValue(operand, diagnostics)
            End If
 
            If operand.HasErrors Then
                ' Suppress any additional diagnostics by overriding DiagnosticBag.
                diagnostics = BindingDiagnosticBag.Discarded
            End If
 
            Dim intrinsicOperatorType As SpecialType = SpecialType.None
            Dim userDefinedOperator As OverloadResolution.OverloadResolutionResult = Nothing
            Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics)
            Dim operatorKind As UnaryOperatorKind = OverloadResolution.ResolveUnaryOperator(preliminaryOperatorKind, operand, Me, intrinsicOperatorType, userDefinedOperator, useSiteInfo)
 
            If diagnostics.Add(node, useSiteInfo) Then
                ' Suppress additional diagnostics
                diagnostics = BindingDiagnosticBag.Discarded
            End If
 
            If operatorKind = UnaryOperatorKind.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.ReturnType)) Then
                    Return BindUserDefinedUnaryOperator(node, preliminaryOperatorKind, operand, userDefinedOperator, diagnostics)
                End If
 
                operatorKind = UnaryOperatorKind.Error
            End If
 
            If operatorKind = UnaryOperatorKind.Error Then
                ReportUndefinedOperatorError(node, operand, diagnostics)
 
                Return New BoundUnaryOperator(node, preliminaryOperatorKind Or UnaryOperatorKind.Error, operand, CheckOverflow, ErrorTypeSymbol.UnknownResultType, HasErrors:=True)
            End If
 
            ' We are dealing with intrinsic operator 
            Dim operandType As TypeSymbol = operand.Type
            Dim resultType As TypeSymbol = Nothing
 
            If intrinsicOperatorType = SpecialType.None Then
                Debug.Assert(operandType.GetNullableUnderlyingTypeOrSelf().IsEnumType())
                resultType = operandType
 
            Else
                If operandType.GetNullableUnderlyingTypeOrSelf().SpecialType = intrinsicOperatorType Then
                    resultType = operandType
                Else
                    resultType = GetSpecialType(intrinsicOperatorType, node.Operand, diagnostics)
 
                    If operandType.IsNullableType() Then
                        resultType = DirectCast(operandType.OriginalDefinition, NamedTypeSymbol).Construct(resultType)
                    End If
                End If
            End If
 
            Debug.Assert(((operatorKind And UnaryOperatorKind.Lifted) <> 0) = resultType.IsNullableType())
 
            ' Option Strict disallows all unary operations on Object operands. Otherwise just warn.
            If operandType.SpecialType = SpecialType.System_Object Then
                If OptionStrict = VisualBasic.OptionStrict.On Then
                    ReportDiagnostic(diagnostics, node.Operand, ErrorFactory.ErrorInfo(ERRID.ERR_StrictDisallowsObjectOperand1, node.OperatorToken))
                ElseIf OptionStrict = VisualBasic.OptionStrict.Custom Then
                    ReportDiagnostic(diagnostics, node.Operand, ErrorFactory.ErrorInfo(ERRID.WRN_ObjectMath2, node.OperatorToken))
                End If
            End If
 
            operand = ApplyImplicitConversion(node.Operand, resultType, operand, diagnostics)
 
            Dim constantValue As ConstantValue = Nothing
 
            If Not operand.HasErrors Then
                Dim integerOverflow As Boolean = False
                constantValue = OverloadResolution.TryFoldConstantUnaryOperator(operatorKind, operand, resultType, integerOverflow)
 
                ' Overflows are reported regardless of the value of OptionRemoveIntegerOverflowChecks, Dev10 behavior.
                If constantValue IsNot Nothing AndAlso (constantValue.IsBad OrElse integerOverflow) Then
                    ReportDiagnostic(diagnostics, node, ErrorFactory.ErrorInfo(ERRID.ERR_ExpressionOverflow1, resultType))
 
                    ' there should be no constant value in case of overflows.
                    If Not constantValue.IsBad Then
                        constantValue = constantValue.Bad
                    End If
                End If
            End If
 
            Return New BoundUnaryOperator(node, operatorKind, operand, CheckOverflow, constantValue, resultType)
        End Function
 
        Private Function BindUserDefinedUnaryOperator(
            node As SyntaxNode,
            opKind As UnaryOperatorKind,
            operand As BoundExpression,
            <[In]> ByRef userDefinedOperator As OverloadResolution.OverloadResolutionResult,
            diagnostics As BindingDiagnosticBag
        ) As BoundUserDefinedUnaryOperator
            Debug.Assert(userDefinedOperator.Candidates.Length > 0)
 
            Dim result As BoundExpression
 
            opKind = opKind Or UnaryOperatorKind.UserDefined
 
            If userDefinedOperator.BestResult.HasValue Then
                Dim bestCandidate As OverloadResolution.CandidateAnalysisResult = userDefinedOperator.BestResult.Value
 
                result = CreateBoundCallOrPropertyAccess(node, node, TypeCharacter.None,
                                                         New BoundMethodGroup(node, Nothing,
                                                                              ImmutableArray.Create(Of MethodSymbol)(
                                                                                  DirectCast(bestCandidate.Candidate.UnderlyingSymbol, MethodSymbol)),
                                                                              LookupResultKind.Good, Nothing,
                                                                              QualificationKind.Unqualified).MakeCompilerGenerated(),
                                                         ImmutableArray.Create(Of BoundExpression)(operand),
                                                         bestCandidate,
                                                         userDefinedOperator.AsyncLambdaSubToFunctionMismatch,
                                                         diagnostics)
 
                If bestCandidate.Candidate.IsLifted Then
                    opKind = opKind Or UnaryOperatorKind.Lifted
                End If
            Else
                result = ReportOverloadResolutionFailureAndProduceBoundNode(node, LookupResultKind.Good,
                                                                            ImmutableArray.Create(Of BoundExpression)(operand),
                                                                            Nothing, userDefinedOperator, diagnostics,
                                                                            callerInfoOpt:=Nothing)
            End If
 
            Return New BoundUserDefinedUnaryOperator(node, opKind, result, result.Type)
        End Function
 
        Private Shared Sub ReportUndefinedOperatorError(
            syntax As UnaryExpressionSyntax,
            operand As BoundExpression,
            diagnostics As BindingDiagnosticBag
        )
            If operand.Type.IsErrorType() Then
                Return ' Let's not report more errors.
            End If
 
            ReportDiagnostic(diagnostics, syntax, ErrorFactory.ErrorInfo(ERRID.ERR_UnaryOperand2, syntax.OperatorToken, operand.Type))
        End Sub
 
    End Class
 
End Namespace