File: Lowering\ExpressionLambdaRewriter\ExpressionLambdaRewriter_BinaryOperator.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 Microsoft.CodeAnalysis.VisualBasic.Symbols
 
Namespace Microsoft.CodeAnalysis.VisualBasic
    Partial Friend Class ExpressionLambdaRewriter
 
        Private Function VisitBinaryOperator(node As BoundBinaryOperator) As BoundExpression
            Debug.Assert((node.OperatorKind And BinaryOperatorKind.UserDefined) = 0)
 
            Select Case node.OperatorKind And BinaryOperatorKind.OpMask
                Case BinaryOperatorKind.And,
                     BinaryOperatorKind.Or,
                     BinaryOperatorKind.Xor,
                     BinaryOperatorKind.Power,
                     BinaryOperatorKind.Multiply,
                     BinaryOperatorKind.Add,
                     BinaryOperatorKind.Subtract,
                     BinaryOperatorKind.Divide,
                     BinaryOperatorKind.Modulo,
                     BinaryOperatorKind.IntegerDivide,
                     BinaryOperatorKind.LeftShift,
                     BinaryOperatorKind.RightShift
                    Return ConvertBinaryOperator(node)
 
                Case BinaryOperatorKind.Is,
                     BinaryOperatorKind.IsNot,
                     BinaryOperatorKind.Equals,
                     BinaryOperatorKind.NotEquals,
                     BinaryOperatorKind.LessThanOrEqual,
                     BinaryOperatorKind.GreaterThanOrEqual,
                     BinaryOperatorKind.LessThan,
                     BinaryOperatorKind.GreaterThan
                    Return ConvertBooleanOperator(node)
 
                Case BinaryOperatorKind.OrElse,
                     BinaryOperatorKind.AndAlso
                    Return ConvertShortCircuitedBooleanOperator(node)
 
                Case BinaryOperatorKind.Like,
                     BinaryOperatorKind.Concatenate
                    ' Should already be rewritten by this time
                    Throw ExceptionUtilities.UnexpectedValue(node.OperatorKind)
 
                Case Else
                    Throw ExceptionUtilities.UnexpectedValue(node.OperatorKind)
            End Select
        End Function
 
        Private Function VisitUserDefinedBinaryOperator(node As BoundUserDefinedBinaryOperator) As BoundExpression
            Dim opKind As BinaryOperatorKind = node.OperatorKind And BinaryOperatorKind.OpMask
            Dim isLifted As Boolean = (node.OperatorKind And BinaryOperatorKind.Lifted) <> 0
            Dim isChecked As Boolean = node.Checked AndAlso IsIntegralType(node.Call.Method.ReturnType)
 
            Select Case opKind
                Case BinaryOperatorKind.Like,
                     BinaryOperatorKind.Concatenate
                    Return ConvertUserDefinedLikeOrConcate(node)
 
                Case BinaryOperatorKind.Is,
                     BinaryOperatorKind.IsNot,
                     BinaryOperatorKind.Equals,
                     BinaryOperatorKind.NotEquals,
                     BinaryOperatorKind.LessThanOrEqual,
                     BinaryOperatorKind.GreaterThanOrEqual,
                     BinaryOperatorKind.LessThan,
                     BinaryOperatorKind.GreaterThan
 
                    ' Error should have been reported by DiagnosticsPass, see 
                    '       DiagnosticsPass.VisitUserDefinedBinaryOperator
                    Debug.Assert(Not isLifted OrElse Not node.Call.Method.ReturnType.IsNullableType)
 
                    Return ConvertRuntimeHelperToExpressionTree(GetComparisonBinaryOperatorFactoryWithMethodInfo(opKind),
                                                                Visit(node.Left), Visit(node.Right),
                                                                Me._factory.Literal(isLifted),
                                                                _factory.MethodInfo(node.Call.Method, _factory.WellKnownType(WellKnownType.System_Reflection_MethodInfo)))
 
                Case Else
                    ' Error should have been reported by DiagnosticsPass, see 
                    '       DiagnosticsPass.VisitUserDefinedBinaryOperator
                    Debug.Assert(Not isLifted OrElse Not node.Call.Method.ReturnType.IsNullableType)
 
                    Return ConvertRuntimeHelperToExpressionTree(GetNonComparisonBinaryOperatorFactoryWithMethodInfo(opKind, isChecked),
                                                                Visit(node.Left), Visit(node.Right),
                                                                _factory.MethodInfo(node.Call.Method, _factory.WellKnownType(WellKnownType.System_Reflection_MethodInfo)))
            End Select
        End Function
 
        Private Shared Function GetComparisonBinaryOperatorFactoryWithMethodInfo(opKind As BinaryOperatorKind) As WellKnownMember
            Select Case opKind And BinaryOperatorKind.OpMask
                Case BinaryOperatorKind.Is,
                     BinaryOperatorKind.Equals
                    Return WellKnownMember.System_Linq_Expressions_Expression__Equal_MethodInfo
 
                Case BinaryOperatorKind.IsNot,
                     BinaryOperatorKind.NotEquals
                    Return WellKnownMember.System_Linq_Expressions_Expression__NotEqual_MethodInfo
 
                Case BinaryOperatorKind.LessThanOrEqual
                    Return WellKnownMember.System_Linq_Expressions_Expression__LessThanOrEqual_MethodInfo
 
                Case BinaryOperatorKind.GreaterThanOrEqual
                    Return WellKnownMember.System_Linq_Expressions_Expression__GreaterThanOrEqual_MethodInfo
 
                Case BinaryOperatorKind.LessThan
                    Return WellKnownMember.System_Linq_Expressions_Expression__LessThan_MethodInfo
 
                Case BinaryOperatorKind.GreaterThan
                    Return WellKnownMember.System_Linq_Expressions_Expression__GreaterThan_MethodInfo
 
                Case Else
                    Throw ExceptionUtilities.UnexpectedValue(opKind)
            End Select
        End Function
 
        Private Shared Function GetNonComparisonBinaryOperatorFactoryWithMethodInfo(opKind As BinaryOperatorKind, isChecked As Boolean) As WellKnownMember
            Select Case opKind And BinaryOperatorKind.OpMask
                Case BinaryOperatorKind.Add
                    Return If(isChecked,
                              WellKnownMember.System_Linq_Expressions_Expression__AddChecked_MethodInfo,
                              WellKnownMember.System_Linq_Expressions_Expression__Add_MethodInfo)
 
                Case BinaryOperatorKind.Subtract
                    Return If(isChecked,
                              WellKnownMember.System_Linq_Expressions_Expression__SubtractChecked_MethodInfo,
                              WellKnownMember.System_Linq_Expressions_Expression__Subtract_MethodInfo)
 
                Case BinaryOperatorKind.Multiply
                    Return If(isChecked,
                              WellKnownMember.System_Linq_Expressions_Expression__MultiplyChecked_MethodInfo,
                              WellKnownMember.System_Linq_Expressions_Expression__Multiply_MethodInfo)
 
                Case BinaryOperatorKind.IntegerDivide,
                     BinaryOperatorKind.Divide
                    Return WellKnownMember.System_Linq_Expressions_Expression__Divide_MethodInfo
 
                Case BinaryOperatorKind.Modulo
                    Return WellKnownMember.System_Linq_Expressions_Expression__Modulo_MethodInfo
 
                Case BinaryOperatorKind.Power
                    Return WellKnownMember.System_Linq_Expressions_Expression__Power_MethodInfo
 
                Case BinaryOperatorKind.And
                    Return WellKnownMember.System_Linq_Expressions_Expression__And_MethodInfo
 
                Case BinaryOperatorKind.Or
                    Return WellKnownMember.System_Linq_Expressions_Expression__Or_MethodInfo
 
                Case BinaryOperatorKind.Xor
                    Return WellKnownMember.System_Linq_Expressions_Expression__ExclusiveOr_MethodInfo
 
                Case BinaryOperatorKind.LeftShift
                    Return WellKnownMember.System_Linq_Expressions_Expression__LeftShift_MethodInfo
 
                Case BinaryOperatorKind.RightShift
                    Return WellKnownMember.System_Linq_Expressions_Expression__RightShift_MethodInfo
 
                Case Else
                    Throw ExceptionUtilities.UnexpectedValue(opKind)
            End Select
        End Function
 
        Private Function VisitUserDefinedShortCircuitingOperator(node As BoundUserDefinedShortCircuitingOperator) As BoundExpression
            Dim operand As BoundUserDefinedBinaryOperator = node.BitwiseOperator
            Dim opKind As BinaryOperatorKind = operand.OperatorKind And BinaryOperatorKind.OpMask
 
            ' See comment in DiagnosticsPass.VisitUserDefinedShortCircuitingOperator
            Debug.Assert(operand.Call.Method.ReturnType.IsSameTypeIgnoringAll(operand.Call.Method.Parameters(0).Type) AndAlso
                         operand.Call.Method.ReturnType.IsSameTypeIgnoringAll(operand.Call.Method.Parameters(1).Type))
 
            Return ConvertRuntimeHelperToExpressionTree(If(opKind = BinaryOperatorKind.And,
                                                           WellKnownMember.System_Linq_Expressions_Expression__AndAlso_MethodInfo,
                                                           WellKnownMember.System_Linq_Expressions_Expression__OrElse_MethodInfo),
                                                        Visit(operand.Left), Visit(operand.Right),
                                                        _factory.MethodInfo(operand.Call.Method, _factory.WellKnownType(WellKnownType.System_Reflection_MethodInfo)))
        End Function
 
#Region "User Defined Like"
 
        Private Function ConvertUserDefinedLikeOrConcate(node As BoundUserDefinedBinaryOperator) As BoundExpression
            Dim [call] As BoundCall = node.Call
            Dim opKind As BinaryOperatorKind = node.OperatorKind
 
            If (opKind And BinaryOperatorKind.Lifted) = 0 Then
                Return VisitInternal([call])
            End If
 
            Return VisitInternal(AdjustCallForLiftedOperator(opKind, [call], node.Type))
        End Function
 
#End Region
 
#Region "Is, IsNot, <, <=, >=, >"
 
        Private Function ConvertBooleanOperator(node As BoundBinaryOperator) As BoundExpression
            Dim resultType As TypeSymbol = node.Type
 
            Dim resultNotNullableType As TypeSymbol = resultType.GetNullableUnderlyingTypeOrSelf
            Dim resultUnderlyingType As TypeSymbol = resultNotNullableType.GetEnumUnderlyingTypeOrSelf
            Dim resultUnderlyingSpecialType As SpecialType = resultUnderlyingType.SpecialType
 
            Dim opKind = node.OperatorKind And BinaryOperatorKind.OpMask
            Debug.Assert(opKind = BinaryOperatorKind.Is OrElse opKind = BinaryOperatorKind.IsNot OrElse
                         opKind = BinaryOperatorKind.Equals OrElse opKind = BinaryOperatorKind.NotEquals OrElse
                         opKind = BinaryOperatorKind.LessThan OrElse opKind = BinaryOperatorKind.GreaterThan OrElse
                         opKind = BinaryOperatorKind.LessThanOrEqual OrElse opKind = BinaryOperatorKind.GreaterThanOrEqual)
            Debug.Assert((node.OperatorKind And BinaryOperatorKind.UserDefined) = 0)
 
            ' Prepare left and right
            Dim originalLeft As BoundExpression = node.Left
            Dim operandType As TypeSymbol = originalLeft.Type
 
            Dim left As BoundExpression = Nothing
            Dim originalRight As BoundExpression = node.Right
            Dim right As BoundExpression = Nothing
 
            Dim isIsIsNot As Boolean = (opKind = BinaryOperatorKind.Is) OrElse (opKind = BinaryOperatorKind.IsNot)
 
            If isIsIsNot Then
                ' Ensure Nothing literals is converted to the type of an opposite operand
                If originalLeft.IsNothingLiteral Then
                    If originalRight.Type.IsNullableType Then
                        Debug.Assert(originalLeft.Type Is Nothing OrElse originalLeft.Type.IsObjectType)
                        left = CreateLiteralExpression(originalLeft, originalRight.Type)
                        operandType = originalRight.Type
                    End If
 
                ElseIf originalRight.IsNothingLiteral Then
                    If originalLeft.Type.IsNullableType Then
                        Debug.Assert(originalRight.Type Is Nothing OrElse originalRight.Type.IsObjectType)
                        right = CreateLiteralExpression(originalRight, originalLeft.Type)
                    End If
                End If
            End If
 
            Dim operandIsNullable As Boolean = operandType.IsNullableType
            Dim operandNotNullableType As TypeSymbol = operandType.GetNullableUnderlyingTypeOrSelf
            Dim operandUnderlyingType As TypeSymbol = operandNotNullableType.GetEnumUnderlyingTypeOrSelf
            Dim operandUnderlyingSpecialType As SpecialType = operandUnderlyingType.SpecialType
 
            If left Is Nothing Then
                left = Visit(originalLeft)
                Debug.Assert(TypeSymbol.Equals(operandType, originalLeft.Type, TypeCompareKind.ConsiderEverything))
            End If
 
            If right Is Nothing Then
                right = Visit(originalRight)
                Debug.Assert(TypeSymbol.Equals(operandType, originalRight.Type, TypeCompareKind.ConsiderEverything))
            End If
 
            ' Do we need to handle special cases?
            Dim helper As MethodSymbol = Nothing
 
            ' [>|>=|<|<=] with System.Object argument should already be rewritten into proper calls
            Debug.Assert(operandUnderlyingSpecialType <> SpecialType.System_Object OrElse isIsIsNot)
 
            ' All boolean operators with System.String argument should already be rewritten into proper calls
            Debug.Assert(operandUnderlyingSpecialType <> SpecialType.System_String)
 
            If operandUnderlyingSpecialType = SpecialType.System_Decimal Then
                helper = GetHelperForDecimalBinaryOperation(opKind)
            ElseIf operandUnderlyingSpecialType = SpecialType.System_DateTime Then
                helper = GetHelperForDateTimeBinaryOperation(opKind)
            End If
 
            If helper IsNot Nothing Then
                Debug.Assert(helper.MethodKind = MethodKind.Ordinary OrElse helper.MethodKind = MethodKind.UserDefinedOperator)
 
                Return ConvertRuntimeHelperToExpressionTree(GetComparisonBinaryOperatorFactoryWithMethodInfo(opKind),
                                                            left, right, Me._factory.Literal(resultType.IsNullableType), _factory.MethodInfo(helper, _factory.WellKnownType(WellKnownType.System_Reflection_MethodInfo)))
            End If
 
            ' No helpers starting from here
 
            Dim convertOperandsToInteger As Boolean = False
            If operandUnderlyingSpecialType = SpecialType.System_Boolean Then
                ' For LT, LE, GT, and GE, if both the arguments are boolean arguments,
                ' we must generate a conversion from the boolean argument to an integer.
 
                ' Because True is -1, we need to switch the comparisons in these cases.
                Select Case opKind
                    Case BinaryOperatorKind.LessThan
                        opKind = BinaryOperatorKind.GreaterThan
                        convertOperandsToInteger = True
 
                    Case BinaryOperatorKind.LessThanOrEqual
                        opKind = BinaryOperatorKind.GreaterThanOrEqual
                        convertOperandsToInteger = True
 
                    Case BinaryOperatorKind.GreaterThan
                        opKind = BinaryOperatorKind.LessThan
                        convertOperandsToInteger = True
 
                    Case BinaryOperatorKind.GreaterThanOrEqual
                        opKind = BinaryOperatorKind.LessThanOrEqual
                        convertOperandsToInteger = True
                End Select
            End If
 
            Dim operandActiveType As TypeSymbol = operandType
 
            ' Convert arguments to underlying type if they are enums
            If operandNotNullableType.IsEnumType AndAlso Not isIsIsNot Then
                ' Assuming both operands are of the same type
                Dim newType As TypeSymbol = If(operandIsNullable, Me._factory.NullableOf(operandUnderlyingType), operandUnderlyingType)
 
                left = CreateBuiltInConversion(operandActiveType, newType, left, node.Checked, False, ConversionSemantics.[Default])
                right = CreateBuiltInConversion(operandActiveType, newType, right, node.Checked, False, ConversionSemantics.[Default])
 
                operandActiveType = newType
            End If
 
            ' Check if we need to convert the boolean arguments to Int32.
            If convertOperandsToInteger AndAlso Not isIsIsNot Then
                Dim newType As TypeSymbol = If(operandIsNullable, Me._factory.NullableOf(Me.Int32Type), Me.Int32Type)
                left = Convert(left, newType, node.Checked)
                right = Convert(right, newType, node.Checked)
                operandActiveType = newType
            End If
 
            Return ConvertRuntimeHelperToExpressionTree(GetComparisonBinaryOperatorFactoryWithMethodInfo(opKind),
                                                        left, right, Me._factory.Literal(resultType.IsNullableType),
                                                        Me._factory.Null(_factory.WellKnownType(WellKnownType.System_Reflection_MethodInfo)))
        End Function
 
#End Region
 
#Region "AndAlso, OrElse"
 
        Private Function ConvertShortCircuitedBooleanOperator(node As BoundBinaryOperator) As BoundExpression
            Dim resultType As TypeSymbol = node.Type
 
            Dim resultUnderlyingType As TypeSymbol = GetUnderlyingType(resultType)
            Dim resultUnderlyingSpecialType As SpecialType = resultUnderlyingType.SpecialType
 
            Dim opKind = node.OperatorKind And BinaryOperatorKind.OpMask
            Debug.Assert(opKind = BinaryOperatorKind.AndAlso OrElse opKind = BinaryOperatorKind.OrElse)
            Debug.Assert((node.OperatorKind And BinaryOperatorKind.UserDefined) = 0)
 
            Dim originalLeft As BoundExpression = node.Left
            Dim left As BoundExpression = Visit(originalLeft)
            Debug.Assert(TypeSymbol.Equals(resultType, originalLeft.Type, TypeCompareKind.ConsiderEverything))
 
            Dim originalRight As BoundExpression = node.Right
            Dim right As BoundExpression = Visit(originalRight)
            Debug.Assert(TypeSymbol.Equals(resultType, originalRight.Type, TypeCompareKind.ConsiderEverything))
 
            If resultUnderlyingType.IsObjectType Then
                Dim systemBool As TypeSymbol = _factory.SpecialType(SpecialType.System_Boolean)
                left = CreateBuiltInConversion(resultType, systemBool, left, node.Checked, False, ConversionSemantics.[Default])
                right = CreateBuiltInConversion(resultType, systemBool, right, node.Checked, False, ConversionSemantics.[Default])
            End If
 
            Dim isChecked As Boolean = node.Checked AndAlso IsIntegralType(resultUnderlyingType)
            Dim opFactory As WellKnownMember
 
            Select Case opKind
                Case BinaryOperatorKind.AndAlso
                    opFactory = WellKnownMember.System_Linq_Expressions_Expression__AndAlso
                Case BinaryOperatorKind.OrElse
                    opFactory = WellKnownMember.System_Linq_Expressions_Expression__OrElse
                Case Else
                    Throw ExceptionUtilities.UnexpectedValue(opKind)
            End Select
 
            Dim result As BoundExpression = ConvertRuntimeHelperToExpressionTree(opFactory, left, right)
 
            If resultUnderlyingType.IsObjectType Then
                result = Convert(result, resultType, isChecked)
            End If
 
            Return result
        End Function
 
#End Region
 
#Region "And, Or, Xor, ^, *, +, -, /, \, Mod, <<, >>"
 
        Private Function ConvertBinaryOperator(node As BoundBinaryOperator) As BoundExpression
            Dim resultType As TypeSymbol = node.Type
 
            Dim resultNotNullableType As TypeSymbol = resultType.GetNullableUnderlyingTypeOrSelf
            Dim resultUnderlyingType As TypeSymbol = resultNotNullableType.GetEnumUnderlyingTypeOrSelf
            Dim resultUnderlyingSpecialType As SpecialType = resultUnderlyingType.SpecialType
 
            Dim opKind = node.OperatorKind And BinaryOperatorKind.OpMask
            Debug.Assert(opKind = BinaryOperatorKind.And OrElse opKind = BinaryOperatorKind.Or OrElse opKind = BinaryOperatorKind.Xor OrElse
                         opKind = BinaryOperatorKind.Power OrElse opKind = BinaryOperatorKind.Multiply OrElse
                         opKind = BinaryOperatorKind.Add OrElse opKind = BinaryOperatorKind.Subtract OrElse
                         opKind = BinaryOperatorKind.Divide OrElse opKind = BinaryOperatorKind.IntegerDivide OrElse
                         opKind = BinaryOperatorKind.Modulo OrElse
                         opKind = BinaryOperatorKind.LeftShift OrElse opKind = BinaryOperatorKind.RightShift)
            Debug.Assert((node.OperatorKind And BinaryOperatorKind.UserDefined) = 0)
 
            ' Do we need to use special helpers?
            Dim helper As MethodSymbol = Nothing
            If resultUnderlyingSpecialType = SpecialType.System_Object Then
                helper = GetHelperForObjectBinaryOperation(opKind)
                If helper Is Nothing Then ' Don't know how to do 'BinaryOperatorKind.Power' without the method
                    Return _factory.BadExpression(Visit(node.Left), Visit(node.Right))
                End If
            ElseIf resultUnderlyingSpecialType = SpecialType.System_Decimal Then
                helper = GetHelperForDecimalBinaryOperation(opKind)
                If helper Is Nothing Then ' Don't know how to do 'BinaryOperatorKind.Power' without the method
                    Return _factory.BadExpression(Visit(node.Left), Visit(node.Right))
                End If
            ElseIf opKind = BinaryOperatorKind.Power Then
                helper = Me._factory.WellKnownMember(Of MethodSymbol)(WellKnownMember.System_Math__PowDoubleDouble)
                If helper Is Nothing Then ' Don't know how to do 'BinaryOperatorKind.Power' without the method
                    Return _factory.BadExpression(Visit(node.Left), Visit(node.Right))
                End If
            End If
 
            Debug.Assert(opKind <> BinaryOperatorKind.Power OrElse helper IsNot Nothing)
 
            Dim isChecked As Boolean = node.Checked AndAlso IsIntegralType(resultUnderlyingType)
 
            Dim left As BoundExpression = Visit(node.Left)
            Dim right As BoundExpression
 
            If helper IsNot Nothing Then
                right = Visit(node.Right)
                Return ConvertRuntimeHelperToExpressionTree(GetNonComparisonBinaryOperatorFactoryWithMethodInfo(opKind, isChecked),
                                                           left, right, _factory.MethodInfo(helper, _factory.WellKnownType(WellKnownType.System_Reflection_MethodInfo)))
            End If
 
            ' No special helper
            Dim resultTypeIsNullable As Boolean = resultType.IsNullableType
            Dim needToCastBackToByteOrSByte As Boolean = resultUnderlyingSpecialType = SpecialType.System_Byte OrElse
                                                         resultUnderlyingSpecialType = SpecialType.System_SByte
 
            left = GenerateCastsForBinaryAndUnaryOperator(left,
                                                          resultTypeIsNullable,
                                                          resultNotNullableType,
                                                          isChecked AndAlso IsIntegralType(resultUnderlyingType),
                                                          needToCastBackToByteOrSByte)
 
            If opKind = BinaryOperatorKind.LeftShift OrElse opKind = BinaryOperatorKind.RightShift Then
                ' Add mask for right operand of a shift operator.
                right = MaskShiftCountOperand(node, resultType, isChecked)
                isChecked = False  ' final conversion shouldn't be checked for shift operands.
 
            Else
                right = Visit(node.Right)
                right = GenerateCastsForBinaryAndUnaryOperator(right,
                                                               resultTypeIsNullable,
                                                               resultNotNullableType,
                                                               isChecked AndAlso IsIntegralType(resultUnderlyingType),
                                                               needToCastBackToByteOrSByte)
            End If
 
            Dim result As BoundExpression = ConvertRuntimeHelperToExpressionTree(GetNonComparisonBinaryOperatorFactoryWithoutMethodInfo(opKind, isChecked), left, right)
 
            If needToCastBackToByteOrSByte Then
                Debug.Assert(resultUnderlyingSpecialType = SpecialType.System_Byte OrElse resultUnderlyingSpecialType = SpecialType.System_SByte)
                result = Convert(result, If(resultTypeIsNullable, Me._factory.NullableOf(resultUnderlyingType), resultUnderlyingType), isChecked)
            End If
 
            If resultNotNullableType.IsEnumType Then
                result = Convert(result, resultType, False)
            End If
 
            Return result
        End Function
 
        Private Shared Function GetNonComparisonBinaryOperatorFactoryWithoutMethodInfo(opKind As BinaryOperatorKind, isChecked As Boolean) As WellKnownMember
            Select Case opKind And BinaryOperatorKind.OpMask
                Case BinaryOperatorKind.Add
                    Return If(isChecked,
                              WellKnownMember.System_Linq_Expressions_Expression__AddChecked,
                              WellKnownMember.System_Linq_Expressions_Expression__Add)
 
                Case BinaryOperatorKind.Subtract
                    Return If(isChecked,
                              WellKnownMember.System_Linq_Expressions_Expression__SubtractChecked,
                              WellKnownMember.System_Linq_Expressions_Expression__Subtract)
 
                Case BinaryOperatorKind.Multiply
                    Return If(isChecked,
                              WellKnownMember.System_Linq_Expressions_Expression__MultiplyChecked,
                              WellKnownMember.System_Linq_Expressions_Expression__Multiply)
 
                Case BinaryOperatorKind.IntegerDivide,
                     BinaryOperatorKind.Divide
                    Return WellKnownMember.System_Linq_Expressions_Expression__Divide
 
                Case BinaryOperatorKind.Modulo
                    Return WellKnownMember.System_Linq_Expressions_Expression__Modulo
 
                Case BinaryOperatorKind.And
                    Return WellKnownMember.System_Linq_Expressions_Expression__And
 
                Case BinaryOperatorKind.Or
                    Return WellKnownMember.System_Linq_Expressions_Expression__Or
 
                Case BinaryOperatorKind.Xor
                    Return WellKnownMember.System_Linq_Expressions_Expression__ExclusiveOr
 
                Case BinaryOperatorKind.LeftShift
                    Return WellKnownMember.System_Linq_Expressions_Expression__LeftShift
 
                Case BinaryOperatorKind.RightShift
                    Return WellKnownMember.System_Linq_Expressions_Expression__RightShift
 
                Case Else
                    Throw ExceptionUtilities.UnexpectedValue(opKind)
            End Select
        End Function
 
        Private Function GenerateCastsForBinaryAndUnaryOperator(loweredOperand As BoundExpression,
                                                                isNullable As Boolean,
                                                                notNullableType As TypeSymbol,
                                                                checked As Boolean,
                                                                needToCastBackToByteOrSByte As Boolean) As BoundExpression
 
            ' Convert enums to their underlying types
            If notNullableType.IsEnumType Then
                Dim underlyingType As TypeSymbol = notNullableType.GetEnumUnderlyingTypeOrSelf
                loweredOperand = Convert(loweredOperand, If(isNullable, Me._factory.NullableOf(underlyingType), underlyingType), False)
            End If
 
            ' Byte and SByte promote operators to Int32, then demote after
            If needToCastBackToByteOrSByte Then
                loweredOperand = Convert(loweredOperand, If(isNullable, Me._factory.NullableOf(Me.Int32Type), Me.Int32Type), checked)
            End If
 
            Return loweredOperand
        End Function
 
        Private Function MaskShiftCountOperand(node As BoundBinaryOperator, resultType As TypeSymbol, isChecked As Boolean) As BoundExpression
            Dim result As BoundExpression = Nothing
 
            ' NOTE: In case we have lifted binary operator, the original non-nullable right operand 
            '       might be already converted to correspondent nullable type; we want to disregard 
            '       such conversion before applying the mask and re-apply it after that
            Dim applyConversionToNullable As Boolean = False
            Dim originalRight As BoundExpression = node.Right
 
            Debug.Assert(Not resultType.GetNullableUnderlyingTypeOrSelf().IsEnumType)
            Dim shiftMask As Integer = CodeGen.CodeGenerator.GetShiftSizeMask(resultType.GetNullableUnderlyingTypeOrSelf())
 
            Dim shiftedType As TypeSymbol = resultType
 
            If resultType.IsNullableType AndAlso originalRight.Kind = BoundKind.Conversion Then
                Dim conversion = DirectCast(originalRight, BoundConversion)
                Dim operand As BoundExpression = conversion.Operand
                Dim operandType As TypeSymbol = operand.Type
 
                If ((conversion.ConversionKind And ConversionKind.Nullable) <> 0) AndAlso Not conversion.ExplicitCastInCode AndAlso Not operandType.IsNullableType Then
                    Debug.Assert(conversion.Type.IsNullableType AndAlso conversion.Type.GetNullableUnderlyingType.SpecialType = SpecialType.System_Int32)
 
                    ' type of the right operand before conversion
                    shiftedType = operandType.GetEnumUnderlyingTypeOrSelf()
 
                    ' visit and convert operand
                    result = Visit(operand)
                    If Not TypeSymbol.Equals(operandType, Me.Int32Type, TypeCompareKind.ConsiderEverything) Then
                        result = CreateBuiltInConversion(operandType, Me.Int32Type, result, isChecked, False, ConversionSemantics.[Default])
                    End If
 
                    applyConversionToNullable = True
                End If
            End If
 
            If Not applyConversionToNullable Then
                result = Visit(originalRight)
            End If
 
            ' Add mask for right operand of a shift operator.
            result = MaskShiftCountOperand(result, shiftedType, shiftMask, result.ConstantValueOpt, isChecked)
 
            If applyConversionToNullable Then
                result = Convert(result, Me._factory.NullableOf(Me.Int32Type), isChecked)
            End If
 
            Return result
        End Function
 
        ''' <summary>
        ''' The shift count for a left-shift or right-shift operator needs to be masked according to the type 
        ''' of the left hand side, unless the shift count is an in-range constant. This is similar to what is 
        ''' done in code gen.
        ''' </summary>
        Private Function MaskShiftCountOperand(loweredOperand As BoundExpression, shiftedType As TypeSymbol, shiftMask As Integer, shiftConst As ConstantValue, isChecked As Boolean) As BoundExpression
            If shiftConst Is Nothing OrElse shiftConst.UInt32Value > shiftMask Then
                Dim constantOperand As BoundExpression =
                    _factory.Convert(_expressionType,
                                     ConvertRuntimeHelperToExpressionTree(
                                        WellKnownMember.System_Linq_Expressions_Expression__Constant,
                                        Me._factory.Convert(Me.ObjectType, Me._factory.Literal(shiftMask)),
                                        Me._factory.Typeof(Me.Int32Type, _factory.WellKnownType(WellKnownType.System_Type))))
 
                Dim isNullable As Boolean = shiftedType.IsNullableType
                Dim isInt32 As Boolean = shiftedType.GetNullableUnderlyingTypeOrSelf.SpecialType = SpecialType.System_Int32
 
                Dim int32Nullable As TypeSymbol = If(isNullable, Me._factory.NullableOf(Me.Int32Type), Nothing)
 
                If isNullable Then
                    constantOperand = Convert(constantOperand, int32Nullable, isChecked)
                End If
 
                loweredOperand = _factory.Convert(_expressionType,
                                                  ConvertRuntimeHelperToExpressionTree(
                                                      WellKnownMember.System_Linq_Expressions_Expression__And,
                                                      loweredOperand,
                                                      constantOperand))
            End If
 
            Return loweredOperand
        End Function
 
#End Region
 
#Region "Utility"
 
        Private Function GetHelperForDecimalBinaryOperation(opKind As BinaryOperatorKind) As MethodSymbol
            opKind = opKind And BinaryOperatorKind.OpMask
 
            Dim specialHelper As SpecialMember
            Select Case opKind
                Case BinaryOperatorKind.Add
                    specialHelper = SpecialMember.System_Decimal__AddDecimalDecimal
                Case BinaryOperatorKind.Subtract
                    specialHelper = SpecialMember.System_Decimal__SubtractDecimalDecimal
                Case BinaryOperatorKind.Multiply
                    specialHelper = SpecialMember.System_Decimal__MultiplyDecimalDecimal
                Case BinaryOperatorKind.Divide
                    specialHelper = SpecialMember.System_Decimal__DivideDecimalDecimal
                Case BinaryOperatorKind.Modulo
                    specialHelper = SpecialMember.System_Decimal__ModuloDecimalDecimal
 
                Case BinaryOperatorKind.Equals,
                     BinaryOperatorKind.Is
                    specialHelper = SpecialMember.System_Decimal__op_Equality
                Case BinaryOperatorKind.NotEquals,
                     BinaryOperatorKind.IsNot
                    specialHelper = SpecialMember.System_Decimal__op_Inequality
                Case BinaryOperatorKind.LessThan
                    specialHelper = SpecialMember.System_Decimal__op_LessThan
                Case BinaryOperatorKind.LessThanOrEqual
                    specialHelper = SpecialMember.System_Decimal__op_LessThanOrEqual
                Case BinaryOperatorKind.GreaterThan
                    specialHelper = SpecialMember.System_Decimal__op_GreaterThan
                Case BinaryOperatorKind.GreaterThanOrEqual
                    specialHelper = SpecialMember.System_Decimal__op_GreaterThanOrEqual
                Case Else
                    Throw ExceptionUtilities.UnexpectedValue(opKind)
            End Select
 
            Return DirectCast(_factory.SpecialMember(specialHelper), MethodSymbol)
        End Function
 
        Private Function GetHelperForDateTimeBinaryOperation(opKind As BinaryOperatorKind) As MethodSymbol
            opKind = opKind And BinaryOperatorKind.OpMask
 
            Dim specialHelper As SpecialMember
            Select Case opKind
                Case BinaryOperatorKind.Equals,
                     BinaryOperatorKind.Is
                    specialHelper = SpecialMember.System_DateTime__op_Equality
                Case BinaryOperatorKind.NotEquals,
                     BinaryOperatorKind.IsNot
                    specialHelper = SpecialMember.System_DateTime__op_Inequality
                Case BinaryOperatorKind.LessThan
                    specialHelper = SpecialMember.System_DateTime__op_LessThan
                Case BinaryOperatorKind.LessThanOrEqual
                    specialHelper = SpecialMember.System_DateTime__op_LessThanOrEqual
                Case BinaryOperatorKind.GreaterThan
                    specialHelper = SpecialMember.System_DateTime__op_GreaterThan
                Case BinaryOperatorKind.GreaterThanOrEqual
                    specialHelper = SpecialMember.System_DateTime__op_GreaterThanOrEqual
 
                Case Else
                    Throw ExceptionUtilities.UnexpectedValue(opKind)
            End Select
 
            Return DirectCast(_factory.SpecialMember(specialHelper), MethodSymbol)
        End Function
 
        Private Function GetHelperForObjectBinaryOperation(opKind As BinaryOperatorKind) As MethodSymbol
            opKind = opKind And BinaryOperatorKind.OpMask
 
            Dim wellKnownHelper As WellKnownMember
            Select Case opKind
                Case BinaryOperatorKind.Add
                    wellKnownHelper = WellKnownMember.Microsoft_VisualBasic_CompilerServices_Operators__AddObjectObjectObject
                Case BinaryOperatorKind.Subtract
                    wellKnownHelper = WellKnownMember.Microsoft_VisualBasic_CompilerServices_Operators__SubtractObjectObjectObject
                Case BinaryOperatorKind.Multiply
                    wellKnownHelper = WellKnownMember.Microsoft_VisualBasic_CompilerServices_Operators__MultiplyObjectObjectObject
                Case BinaryOperatorKind.Divide
                    wellKnownHelper = WellKnownMember.Microsoft_VisualBasic_CompilerServices_Operators__DivideObjectObjectObject
                Case BinaryOperatorKind.IntegerDivide
                    wellKnownHelper = WellKnownMember.Microsoft_VisualBasic_CompilerServices_Operators__IntDivideObjectObjectObject
                Case BinaryOperatorKind.Modulo
                    wellKnownHelper = WellKnownMember.Microsoft_VisualBasic_CompilerServices_Operators__ModObjectObjectObject
                Case BinaryOperatorKind.Power
                    wellKnownHelper = WellKnownMember.Microsoft_VisualBasic_CompilerServices_Operators__ExponentObjectObjectObject
                Case BinaryOperatorKind.And
                    wellKnownHelper = WellKnownMember.Microsoft_VisualBasic_CompilerServices_Operators__AndObjectObjectObject
                Case BinaryOperatorKind.Xor
                    wellKnownHelper = WellKnownMember.Microsoft_VisualBasic_CompilerServices_Operators__XorObjectObjectObject
                Case BinaryOperatorKind.Or
                    wellKnownHelper = WellKnownMember.Microsoft_VisualBasic_CompilerServices_Operators__OrObjectObjectObject
                Case BinaryOperatorKind.LeftShift
                    wellKnownHelper = WellKnownMember.Microsoft_VisualBasic_CompilerServices_Operators__LeftShiftObjectObjectObject
                Case BinaryOperatorKind.RightShift
                    wellKnownHelper = WellKnownMember.Microsoft_VisualBasic_CompilerServices_Operators__RightShiftObjectObjectObject
                Case BinaryOperatorKind.Concatenate
                    wellKnownHelper = WellKnownMember.Microsoft_VisualBasic_CompilerServices_Operators__ConcatenateObjectObjectObject
 
                Case Else
                    Throw ExceptionUtilities.UnexpectedValue(opKind)
            End Select
 
            Return Me._factory.WellKnownMember(Of MethodSymbol)(wellKnownHelper)
        End Function
 
        Private Shared Function AdjustCallArgumentForLiftedOperator(oldArg As BoundExpression, parameterType As TypeSymbol) As BoundExpression
            Debug.Assert(oldArg.Type.IsNullableType)
            Debug.Assert(Not parameterType.IsNullableType)
            Debug.Assert(TypeSymbol.Equals(oldArg.Type.GetNullableUnderlyingTypeOrSelf(), parameterType, TypeCompareKind.ConsiderEverything))
 
            If oldArg.Kind = BoundKind.ObjectCreationExpression Then
                Dim objCreation = DirectCast(oldArg, BoundObjectCreationExpression)
                ' Nullable<T> has only one ctor with parameters and only that one sets hasValue = true
                If objCreation.Arguments.Length = 1 Then
                    Return objCreation.Arguments(0)
                End If
            End If
 
            ' Else just wrap in conversion
            Return New BoundConversion(oldArg.Syntax, oldArg, ConversionKind.NarrowingNullable, False, False, parameterType)
        End Function
 
        Private Function AdjustCallForLiftedOperator(opKind As BinaryOperatorKind, [call] As BoundCall, resultType As TypeSymbol) As BoundExpression
            Debug.Assert((opKind And BinaryOperatorKind.Lifted) <> 0)
            Debug.Assert((opKind And BinaryOperatorKind.OpMask) = BinaryOperatorKind.Like OrElse
                         (opKind And BinaryOperatorKind.OpMask) = BinaryOperatorKind.Concatenate)
            Return AdjustCallForLiftedOperator_DoNotCallDirectly([call], resultType)
        End Function
 
        Private Function AdjustCallForLiftedOperator(opKind As UnaryOperatorKind, [call] As BoundCall, resultType As TypeSymbol) As BoundExpression
            Debug.Assert((opKind And UnaryOperatorKind.Lifted) <> 0)
            Debug.Assert((opKind And UnaryOperatorKind.OpMask) = UnaryOperatorKind.IsTrue OrElse
                         (opKind And UnaryOperatorKind.OpMask) = UnaryOperatorKind.IsFalse)
            Return AdjustCallForLiftedOperator_DoNotCallDirectly([call], resultType)
        End Function
 
        Private Function AdjustCallForLiftedOperator_DoNotCallDirectly([call] As BoundCall, resultType As TypeSymbol) As BoundExpression
            ' NOTE: those operators which are not converted into a special factory methods, but rather 
            '       into a direct call we need to adjust the type of operands and the resulting type to 
            '       that of the method. This method is only to be called for particular operators!!!!
 
            Dim parameters As ImmutableArray(Of ParameterSymbol) = [call].Method.Parameters
            Debug.Assert(parameters.Length > 0)
 
            Dim oldArgs As ImmutableArray(Of BoundExpression) = [call].Arguments
            Debug.Assert(parameters.Length = oldArgs.Length)
 
            Dim newArgs(oldArgs.Length - 1) As BoundExpression
            For i = 0 To oldArgs.Length - 1
                newArgs(i) = AdjustCallArgumentForLiftedOperator(oldArgs(i), parameters(i).Type)
            Next
 
            Dim methodReturnType As TypeSymbol = [call].Method.ReturnType
            Debug.Assert(resultType.GetNullableUnderlyingTypeOrSelf().
                         IsSameTypeIgnoringAll(methodReturnType.GetNullableUnderlyingTypeOrSelf))
 
            [call] = [call].Update([call].Method,
                                   [call].MethodGroupOpt,
                                   [call].ReceiverOpt,
                                   newArgs.AsImmutableOrNull,
                                   [call].DefaultArguments,
                                   [call].ConstantValueOpt,
                                   isLValue:=[call].IsLValue,
                                   suppressObjectClone:=[call].SuppressObjectClone,
                                   type:=methodReturnType)
 
            If resultType.IsNullableType <> methodReturnType.IsNullableType Then
                Return Me._factory.Convert(resultType, [call])
            End If
            Return [call]
        End Function
 
#End Region
 
    End Class
End Namespace