File: Binding\Binder_Conversions.vb
Web Access
Project: src\src\roslyn\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.Collections
Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports TypeKind = Microsoft.CodeAnalysis.TypeKind

Namespace Microsoft.CodeAnalysis.VisualBasic

    ' Binding of conversion operators is implemented in this part.

    Partial Friend Class Binder

        Private Function BindCastExpression(
             node As CastExpressionSyntax,
             diagnostics As BindingDiagnosticBag
         ) As BoundExpression

            Dim result As BoundExpression

            Select Case node.Keyword.Kind
                Case SyntaxKind.CTypeKeyword
                    result = BindCTypeExpression(node, diagnostics)

                Case SyntaxKind.DirectCastKeyword
                    result = BindDirectCastExpression(node, diagnostics)

                Case SyntaxKind.TryCastKeyword
                    result = BindTryCastExpression(node, diagnostics)

                Case Else
                    Throw ExceptionUtilities.UnexpectedValue(node.Keyword.Kind)
            End Select

            Return result
        End Function

        Private Function BindCTypeExpression(
             node As CastExpressionSyntax,
             diagnostics As BindingDiagnosticBag
         ) As BoundExpression

            Debug.Assert(node.Keyword.Kind = SyntaxKind.CTypeKeyword)

            Dim argument = BindValue(node.Expression, diagnostics)
            Dim targetType = BindTypeSyntax(node.Type, diagnostics)

            Return ApplyConversion(node, targetType, argument, isExplicit:=True, diagnostics)
        End Function

        Private Function BindDirectCastExpression(
             node As CastExpressionSyntax,
             diagnostics As BindingDiagnosticBag
         ) As BoundExpression

            Debug.Assert(node.Keyword.Kind = SyntaxKind.DirectCastKeyword)

            Dim argument = BindValue(node.Expression, diagnostics)
            Dim targetType = BindTypeSyntax(node.Type, diagnostics)

            Return ApplyDirectCastConversion(node, argument, targetType, diagnostics)
        End Function

        Private Function ApplyDirectCastConversion(
             node As SyntaxNode,
             argument As BoundExpression,
             targetType As TypeSymbol,
             diagnostics As BindingDiagnosticBag
        ) As BoundExpression
            Debug.Assert(argument.IsValue)

            ' Deal with erroneous arguments
            If (argument.HasErrors OrElse targetType.IsErrorType) Then
                argument = MakeRValue(argument, diagnostics)

                Return New BoundDirectCast(node, argument, conversionKind:=Nothing, type:=targetType, hasErrors:=True)
            End If

            ' Classify conversion
            Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics)
            Dim conv As ConversionKind = Conversions.ClassifyDirectCastConversion(argument, targetType, Me, useSiteInfo)

            If diagnostics.Add(node, useSiteInfo) Then
                ' Suppress any additional diagnostics
                diagnostics = BindingDiagnosticBag.Discarded
            End If

            If ReclassifyExpression(argument, SyntaxKind.DirectCastKeyword, node, conv, True, targetType, diagnostics) Then
                If argument.Syntax IsNot node Then
                    ' If its an explicit conversion, we must have a bound node that corresponds to that syntax node for GetSemanticInfo.
                    ' Insert an identity conversion if necessary.
                    Debug.Assert(argument.Kind <> BoundKind.DirectCast, "Associated wrong node with conversion?")
                    argument = New BoundDirectCast(node, argument, ConversionKind.Identity, targetType)
                End If

                Return argument
            Else
                argument = MakeRValue(argument, diagnostics)
            End If

            If argument.HasErrors Then
                Return New BoundDirectCast(node, argument, conv, targetType, hasErrors:=True)
            End If

            Dim sourceType = argument.Type

            If sourceType IsNot Nothing AndAlso sourceType.IsErrorType() Then
                Return New BoundDirectCast(node, argument, conv, targetType, hasErrors:=True)
            End If

            Debug.Assert(argument.IsNothingLiteral() OrElse (sourceType IsNot Nothing AndAlso Not sourceType.IsErrorType()))

            ' Check for special error conditions
            If Conversions.NoConversion(conv) Then
                If sourceType.IsValueType AndAlso sourceType.IsRestrictedType() AndAlso
                       (targetType.IsObjectType() OrElse targetType.SpecialType = SpecialType.System_ValueType) Then
                    ReportDiagnostic(diagnostics, argument.Syntax, ERRID.ERR_RestrictedConversion1, sourceType)
                    Return New BoundDirectCast(node, argument, conv, targetType, hasErrors:=True)
                End If
            End If

            WarnOnNarrowingConversionBetweenSealedClassAndAnInterface(conv, argument.Syntax, sourceType, targetType, diagnostics)

            If Conversions.NoConversion(conv) Then
                ReportNoConversionError(argument.Syntax, sourceType, targetType, diagnostics)
                Return New BoundDirectCast(node, argument, conv, targetType, hasErrors:=True)
            End If

            If Conversions.IsIdentityConversion(conv) Then
                If targetType.IsFloatingType() Then
                    ReportDiagnostic(diagnostics, argument.Syntax, ERRID.ERR_IdentityDirectCastForFloat)

                ElseIf targetType.IsValueType Then
                    ReportDiagnostic(diagnostics, argument.Syntax, ERRID.WRN_ObsoleteIdentityDirectCastForValueType)
                End If
            End If

            Dim integerOverflow As Boolean = False

            Dim constantResult = Conversions.TryFoldConstantConversion(
                                    argument,
                                    targetType,
                                    integerOverflow)

            If constantResult IsNot Nothing Then
                Debug.Assert(Conversions.IsIdentityConversion(conv) OrElse
                                      conv = ConversionKind.WideningNothingLiteral OrElse
                                      sourceType.GetEnumUnderlyingTypeOrSelf().IsSameTypeIgnoringAll(targetType.GetEnumUnderlyingTypeOrSelf()))
                Debug.Assert(Not integerOverflow)
                Debug.Assert(Not constantResult.IsBad)
            Else
                constantResult = Conversions.TryFoldNothingReferenceConversion(argument, conv, targetType)
            End If

            If Not Conversions.IsIdentityConversion(conv) Then
                WarnOnLockConversion(sourceType, argument.Syntax, diagnostics)
            End If

            Return New BoundDirectCast(node, argument, conv, constantResult, targetType)
        End Function

        Private Function BindTryCastExpression(
             node As CastExpressionSyntax,
             diagnostics As BindingDiagnosticBag
         ) As BoundExpression

            Debug.Assert(node.Keyword.Kind = SyntaxKind.TryCastKeyword)

            Dim argument = BindValue(node.Expression, diagnostics)
            Dim targetType = BindTypeSyntax(node.Type, diagnostics)

            Return ApplyTryCastConversion(node, argument, targetType, diagnostics)
        End Function

        Private Function ApplyTryCastConversion(
             node As SyntaxNode,
             argument As BoundExpression,
             targetType As TypeSymbol,
             diagnostics As BindingDiagnosticBag
        ) As BoundExpression
            Debug.Assert(argument.IsValue)

            ' Deal with erroneous arguments
            If (argument.HasErrors OrElse targetType.IsErrorType) Then
                argument = MakeRValue(argument, diagnostics)

                Return New BoundTryCast(node, argument, conversionKind:=Nothing, type:=targetType, hasErrors:=True)
            End If

            ' Classify conversion
            Dim conv As ConversionKind

            If targetType.IsReferenceType Then
                Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics)
                conv = Conversions.ClassifyTryCastConversion(argument, targetType, Me, useSiteInfo)

                If diagnostics.Add(node, useSiteInfo) Then
                    ' Suppress any additional diagnostics
                    diagnostics = BindingDiagnosticBag.Discarded
                End If
            Else
                conv = Nothing
            End If

            If ReclassifyExpression(argument, SyntaxKind.TryCastKeyword, node, conv, True, targetType, diagnostics) Then
                If argument.Syntax IsNot node Then
                    ' If its an explicit conversion, we must have a bound node that corresponds to that syntax node for GetSemanticInfo.
                    ' Insert an identity conversion if necessary.
                    Debug.Assert(argument.Kind <> BoundKind.TryCast, "Associated wrong node with conversion?")
                    argument = New BoundTryCast(node, argument, ConversionKind.Identity, targetType)
                End If

                Return argument
            Else
                argument = MakeRValue(argument, diagnostics)
            End If

            If argument.HasErrors Then
                Return New BoundTryCast(node, argument, conv, targetType, hasErrors:=True)
            End If

            Dim sourceType = argument.Type

            If sourceType IsNot Nothing AndAlso sourceType.IsErrorType() Then
                Return New BoundTryCast(node, argument, conv, targetType, hasErrors:=True)
            End If

            Debug.Assert(argument.IsNothingLiteral() OrElse (sourceType IsNot Nothing AndAlso Not sourceType.IsErrorType()))

            ' Check for special error conditions
            If Conversions.NoConversion(conv) Then
                If targetType.IsValueType() Then
                    Dim castSyntax = TryCast(node, CastExpressionSyntax)
                    ReportDiagnostic(diagnostics, If(castSyntax IsNot Nothing, castSyntax.Type, node), ERRID.ERR_TryCastOfValueType1, targetType)
                    Return New BoundTryCast(node, argument, conv, targetType, hasErrors:=True)

                ElseIf targetType.IsTypeParameter() AndAlso Not targetType.IsReferenceType Then
                    Dim castSyntax = TryCast(node, CastExpressionSyntax)
                    ReportDiagnostic(diagnostics, If(castSyntax IsNot Nothing, castSyntax.Type, node), ERRID.ERR_TryCastOfUnconstrainedTypeParam1, targetType)
                    Return New BoundTryCast(node, argument, conv, targetType, hasErrors:=True)

                ElseIf sourceType.IsValueType AndAlso sourceType.IsRestrictedType() AndAlso
                       (targetType.IsObjectType() OrElse targetType.SpecialType = SpecialType.System_ValueType) Then
                    ReportDiagnostic(diagnostics, argument.Syntax, ERRID.ERR_RestrictedConversion1, sourceType)
                    Return New BoundTryCast(node, argument, conv, targetType, hasErrors:=True)
                End If
            End If

            WarnOnNarrowingConversionBetweenSealedClassAndAnInterface(conv, argument.Syntax, sourceType, targetType, diagnostics)

            If Conversions.NoConversion(conv) Then
                ReportNoConversionError(argument.Syntax, sourceType, targetType, diagnostics)
                Return New BoundTryCast(node, argument, conv, targetType, hasErrors:=True)
            End If

            Dim constantResult = Conversions.TryFoldNothingReferenceConversion(argument, conv, targetType)

            If Not Conversions.IsIdentityConversion(conv) Then
                WarnOnLockConversion(sourceType, argument.Syntax, diagnostics)
            End If

            Return New BoundTryCast(node, argument, conv, constantResult, targetType)
        End Function

        Private Function BindPredefinedCastExpression(
             node As PredefinedCastExpressionSyntax,
             diagnostics As BindingDiagnosticBag
         ) As BoundExpression

            Dim targetType As SpecialType

            Select Case node.Keyword.Kind
                Case SyntaxKind.CBoolKeyword : targetType = SpecialType.System_Boolean
                Case SyntaxKind.CByteKeyword : targetType = SpecialType.System_Byte
                Case SyntaxKind.CCharKeyword : targetType = SpecialType.System_Char
                Case SyntaxKind.CDateKeyword : targetType = SpecialType.System_DateTime
                Case SyntaxKind.CDecKeyword : targetType = SpecialType.System_Decimal
                Case SyntaxKind.CDblKeyword : targetType = SpecialType.System_Double
                Case SyntaxKind.CIntKeyword : targetType = SpecialType.System_Int32
                Case SyntaxKind.CLngKeyword : targetType = SpecialType.System_Int64
                Case SyntaxKind.CObjKeyword : targetType = SpecialType.System_Object
                Case SyntaxKind.CSByteKeyword : targetType = SpecialType.System_SByte
                Case SyntaxKind.CShortKeyword : targetType = SpecialType.System_Int16
                Case SyntaxKind.CSngKeyword : targetType = SpecialType.System_Single
                Case SyntaxKind.CStrKeyword : targetType = SpecialType.System_String
                Case SyntaxKind.CUIntKeyword : targetType = SpecialType.System_UInt32
                Case SyntaxKind.CULngKeyword : targetType = SpecialType.System_UInt64
                Case SyntaxKind.CUShortKeyword : targetType = SpecialType.System_UInt16
                Case Else
                    Throw ExceptionUtilities.UnexpectedValue(node.Keyword.Kind)
            End Select

            Return ApplyConversion(node, GetSpecialType(targetType, node.Keyword, diagnostics),
                                   BindValue(node.Expression, diagnostics),
                                   isExplicit:=True, diagnostics:=diagnostics)
        End Function

        ''' <summary>
        ''' This function must return a BoundConversion node in case of non-identity conversion.
        ''' </summary>
        Friend Function ApplyImplicitConversion(
            node As SyntaxNode,
            targetType As TypeSymbol,
            expression As BoundExpression,
            diagnostics As BindingDiagnosticBag,
            Optional isOperandOfConditionalBranch As Boolean = False
        ) As BoundExpression
            Return ApplyConversion(node, targetType, expression, False, diagnostics, isOperandOfConditionalBranch:=isOperandOfConditionalBranch)
        End Function

        ''' <summary>
        ''' This function must return a BoundConversion node in case of explicit or non-identity conversion.
        ''' </summary>
        Private Function ApplyConversion(
            node As SyntaxNode,
            targetType As TypeSymbol,
            argument As BoundExpression,
            isExplicit As Boolean,
            diagnostics As BindingDiagnosticBag,
            Optional isOperandOfConditionalBranch As Boolean = False,
            Optional explicitSemanticForConcatArgument As Boolean = False
        ) As BoundExpression
            Debug.Assert(node IsNot Nothing)
            Debug.Assert(Not isOperandOfConditionalBranch OrElse Not isExplicit)
            Debug.Assert(argument.IsValue())

            ' Deal with erroneous arguments
            If targetType.IsErrorType Then
                argument = MakeRValueAndIgnoreDiagnostics(argument)

                If Not isExplicit AndAlso argument.Type.IsSameTypeIgnoringAll(targetType) Then
                    Return argument
                End If

                Return New BoundConversion(node,
                                           argument,
                                           conversionKind:=Nothing,
                                           checked:=CheckOverflow,
                                           explicitCastInCode:=isExplicit,
                                           type:=targetType,
                                           hasErrors:=True)
            End If

            If argument.HasErrors Then
                ' Suppress any additional diagnostics produced by this function
                diagnostics = BindingDiagnosticBag.Discarded
            End If

            ' Classify conversion
            Dim conv As KeyValuePair(Of ConversionKind, MethodSymbol)
            Dim applyNullableIsTrueOperator As Boolean = False
            Dim isTrueOperator As OverloadResolution.OverloadResolutionResult = Nothing
            Dim result As BoundExpression

            Debug.Assert(Not isOperandOfConditionalBranch OrElse targetType.IsBooleanType())

            Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics)

            If isOperandOfConditionalBranch AndAlso targetType.IsBooleanType() Then
                Debug.Assert(Not isExplicit)
                conv = Conversions.ClassifyConversionOfOperandOfConditionalBranch(argument, targetType, Me,
                                                                                  applyNullableIsTrueOperator,
                                                                                  isTrueOperator,
                                                                                  useSiteInfo)

                If diagnostics.Add(node, useSiteInfo) Then
                    ' Suppress any additional diagnostics
                    diagnostics = BindingDiagnosticBag.Discarded
                End If

                If isTrueOperator.BestResult.HasValue Then
                    ' Apply IsTrue operator.
                    Dim isTrue As BoundUserDefinedUnaryOperator = BindUserDefinedUnaryOperator(node, UnaryOperatorKind.IsTrue, argument, isTrueOperator, diagnostics)

                    isTrue.SetWasCompilerGenerated()
                    isTrue.UnderlyingExpression.SetWasCompilerGenerated()
                    result = isTrue
                Else
                    Dim intermediateTargetType As TypeSymbol

                    If applyNullableIsTrueOperator Then
                        ' Note, use site error will be reported by ApplyNullableIsTrueOperator later.
                        Dim nullableOfT As NamedTypeSymbol = Compilation.GetSpecialType(SpecialType.System_Nullable_T)
                        intermediateTargetType = Compilation.GetSpecialType(SpecialType.System_Nullable_T).
                                                        Construct(ImmutableArray.Create(Of TypeSymbol)(targetType))
                    Else
                        intermediateTargetType = targetType
                    End If

                    result = CreateConversionAndReportDiagnostic(node, argument, conv, isExplicit, intermediateTargetType, diagnostics)
                End If

                If applyNullableIsTrueOperator Then
                    result = Binder.ApplyNullableIsTrueOperator(result, targetType)
                End If
            Else
                conv = Conversions.ClassifyConversion(argument, targetType, Me, useSiteInfo)

                If diagnostics.Add(node, useSiteInfo) Then
                    ' Suppress any additional diagnostics
                    diagnostics = BindingDiagnosticBag.Discarded
                End If

                result = CreateConversionAndReportDiagnostic(node, argument, conv, isExplicit, targetType, diagnostics,
                                                             explicitSemanticForConcatArgument:=explicitSemanticForConcatArgument)
            End If

            Return result
        End Function

        Private Shared Function ApplyNullableIsTrueOperator(argument As BoundExpression, booleanType As TypeSymbol) As BoundNullableIsTrueOperator
            Debug.Assert(argument.Type.IsNullableOfBoolean() AndAlso booleanType.IsBooleanType())
            Return New BoundNullableIsTrueOperator(argument.Syntax, argument, booleanType).MakeCompilerGenerated()
        End Function

        ''' <summary>
        ''' This function must return a BoundConversion node in case of non-identity conversion.
        ''' </summary>
        Private Function CreateConversionAndReportDiagnostic(
            tree As SyntaxNode,
            argument As BoundExpression,
            convKind As KeyValuePair(Of ConversionKind, MethodSymbol),
            isExplicit As Boolean,
            targetType As TypeSymbol,
            diagnostics As BindingDiagnosticBag,
            Optional copybackConversionParamName As String = Nothing,
            Optional explicitSemanticForConcatArgument As Boolean = False
        ) As BoundExpression
            Debug.Assert(argument.IsValue())

            ' We need to preserve any conversion that was explicitly written in code 
            ' (so that GetSemanticInfo can find the syntax in the bound tree). Implicit identity conversion
            ' don't need representation in the bound tree (they would be optimized away in emit, but are so common
            ' that this is an important way to save both time and memory).
            If (Not isExplicit OrElse explicitSemanticForConcatArgument) AndAlso Conversions.IsIdentityConversion(convKind.Key) Then
                Debug.Assert(argument.Type.IsSameTypeIgnoringAll(targetType))
                Debug.Assert(tree Is argument.Syntax)
                Return MakeRValue(argument, diagnostics)
            End If

            If (convKind.Key And ConversionKind.UserDefined) = 0 AndAlso
               ReclassifyExpression(argument, SyntaxKind.CTypeKeyword, tree, convKind.Key, isExplicit, targetType, diagnostics) Then
                argument = MakeRValue(argument, diagnostics)

                If isExplicit AndAlso argument.Syntax IsNot tree Then
                    ' If its an explicit conversion, we must have a bound node that corresponds to that syntax node for GetSemanticInfo.
                    ' Insert an identity conversion if necessary.
                    Debug.Assert(argument.Kind <> BoundKind.Conversion, "Associated wrong node with conversion?")
                    argument = New BoundConversion(tree, argument, ConversionKind.Identity, CheckOverflow, isExplicit, targetType)
                End If

                Return argument
            ElseIf Not argument.IsNothingLiteral() AndAlso argument.Kind <> BoundKind.ArrayLiteral Then
                argument = MakeRValue(argument, diagnostics)
            End If

            Debug.Assert(argument.Kind <> BoundKind.Conversion OrElse DirectCast(argument, BoundConversion).ExplicitCastInCode OrElse
                         Not argument.IsNothingLiteral() OrElse
                         TypeOf argument.Syntax.Parent Is BinaryExpressionSyntax OrElse
                         TypeOf argument.Syntax.Parent Is UnaryExpressionSyntax OrElse
                         TypeOf argument.Syntax.Parent Is TupleExpressionSyntax OrElse
                         (TypeOf argument.Syntax.Parent Is AssignmentStatementSyntax AndAlso argument.Syntax.Parent.Kind <> SyntaxKind.SimpleAssignmentStatement),
                         "Applying yet another conversion to an implicit conversion from NOTHING, probably MakeRValue was called too early.")

            Dim sourceType = argument.Type

            ' At this point if the expression is an array literal then the conversion must be user defined.
            Debug.Assert(argument.Kind <> BoundKind.ArrayLiteral OrElse (convKind.Key And ConversionKind.UserDefined) <> 0)

            Dim reportArrayLiteralElementNarrowingConversion = False
            If argument.Kind = BoundKind.ArrayLiteral Then
                ' The array will get the type from the input type of the user defined conversion.
                sourceType = convKind.Value.Parameters(0).Type

                ' If the conversion from the inferred element type to the source type of the user defined conversion is a narrowing conversion then
                ' skip to the user defined conversion. Conversion errors on the individual elements will be reported when the array literal is reclassified.
                Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics)
                reportArrayLiteralElementNarrowingConversion =
                    Not isExplicit AndAlso
                    Conversions.IsNarrowingConversion(convKind.Key) AndAlso
                    Conversions.IsNarrowingConversion(Conversions.ClassifyArrayLiteralConversion(DirectCast(argument, BoundArrayLiteral), sourceType, Me, useSiteInfo))

                diagnostics.Add(argument.Syntax, useSiteInfo)

                If reportArrayLiteralElementNarrowingConversion Then
                    GoTo DoneWithDiagnostics
                End If
            End If

            If argument.HasErrors Then
                GoTo DoneWithDiagnostics
            End If

            If sourceType IsNot Nothing AndAlso sourceType.IsErrorType() Then
                GoTo DoneWithDiagnostics
            End If

            Debug.Assert(argument.IsNothingLiteral() OrElse (sourceType IsNot Nothing AndAlso Not sourceType.IsErrorType()))

            ' Check for special error conditions
            If Conversions.NoConversion(convKind.Key) Then
                If sourceType.IsValueType AndAlso sourceType.IsRestrictedType() AndAlso
                       (targetType.IsObjectType() OrElse targetType.SpecialType = SpecialType.System_ValueType) Then
                    ReportDiagnostic(diagnostics, argument.Syntax, ERRID.ERR_RestrictedConversion1, sourceType)
                    Return New BoundConversion(tree, argument, convKind.Key, CheckOverflow, isExplicit, targetType, hasErrors:=True)
                End If
            End If

            WarnOnNarrowingConversionBetweenSealedClassAndAnInterface(convKind.Key, argument.Syntax, sourceType, targetType, diagnostics)

            ' Deal with implicit narrowing conversions
            If Not isExplicit AndAlso Conversions.IsNarrowingConversion(convKind.Key) AndAlso
               (convKind.Key And ConversionKind.InvolvesNarrowingFromNumericConstant) = 0 Then

                If copybackConversionParamName IsNot Nothing Then
                    If OptionStrict = VisualBasic.OptionStrict.On Then
                        ReportDiagnostic(diagnostics, argument.Syntax, ERRID.ERR_StrictArgumentCopyBackNarrowing3,
                                               copybackConversionParamName, sourceType, targetType)
                    ElseIf OptionStrict = VisualBasic.OptionStrict.Custom Then
                        ReportDiagnostic(diagnostics, argument.Syntax, ERRID.WRN_ImplicitConversionCopyBack,
                                               copybackConversionParamName, sourceType, targetType)
                    End If

                Else
                    ' We have a narrowing conversion. This is how we might display it, depending on context:
                    ' ERR_NarrowingConversionDisallowed2 "Option Strict On disallows implicit conversions from '|1' to '|2'."
                    ' ERR_NarrowingConversionCollection2 "Option Strict On disallows implicit conversions from '|1' to '|2'; 
                    '                                     the Visual Basic 6.0 collection type is not compatible with the .NET Framework collection type."
                    ' ERR_AmbiguousCastConversion2       "Option Strict On disallows implicit conversions from '|1' to '|2' because the conversion is ambiguous."
                    ' The Collection error is for when one type is Microsoft.VisualBasic.Collection and
                    ' the other type is named _Collection.
                    ' The Ambiguous error is for when the conversion was classed as "Narrowing" for reasons of ambiguity.

                    If OptionStrict = VisualBasic.OptionStrict.On Then

                        If Not MakeVarianceConversionSuggestion(convKind.Key, argument.Syntax, sourceType, targetType, diagnostics, justWarn:=False) Then
                            Dim err As ERRID = ERRID.ERR_NarrowingConversionDisallowed2
                            Const _Collection As String = "_Collection"

                            If (convKind.Key And ConversionKind.VarianceConversionAmbiguity) <> 0 Then
                                err = ERRID.ERR_AmbiguousCastConversion2
                            ElseIf (sourceType.IsMicrosoftVisualBasicCollection() AndAlso String.Equals(targetType.Name, _Collection, StringComparison.Ordinal)) OrElse
                                    (String.Equals(sourceType.Name, _Collection, StringComparison.Ordinal) AndAlso targetType.IsMicrosoftVisualBasicCollection()) Then
                                ' Got both, so use the more specific error message
                                err = ERRID.ERR_NarrowingConversionCollection2
                            End If

                            ReportDiagnostic(diagnostics, argument.Syntax, err, sourceType, targetType)
                        End If

                    ElseIf OptionStrict = VisualBasic.OptionStrict.Custom Then

                        ' Avoid reporting a warning if narrowing caused exclusively by "zero argument" relaxation
                        ' for an Anonymous Delegate. Note, that dropping a return is widening. 
                        If (convKind.Key And ConversionKind.AnonymousDelegate) = 0 OrElse
                           (convKind.Key And ConversionKind.DelegateRelaxationLevelMask) <> ConversionKind.DelegateRelaxationLevelWideningDropReturnOrArgs Then

                            If Not MakeVarianceConversionSuggestion(convKind.Key, argument.Syntax, sourceType, targetType, diagnostics, justWarn:=True) Then
                                Dim wrnId1 As ERRID = ERRID.WRN_ImplicitConversionSubst1
                                Dim wrnId2 As ERRID = ERRID.WRN_ImplicitConversion2

                                If (convKind.Key And ConversionKind.VarianceConversionAmbiguity) <> 0 Then
                                    wrnId2 = ERRID.WRN_AmbiguousCastConversion2
                                End If

                                ReportDiagnostic(diagnostics, argument.Syntax, wrnId1, ErrorFactory.ErrorInfo(wrnId2, sourceType, targetType))
                            End If
                        End If
                    End If
                End If
            End If

            If Conversions.NoConversion(convKind.Key) Then
                If Conversions.FailedDueToNumericOverflow(convKind.Key) Then
                    Dim errorTargetType As TypeSymbol

                    If (convKind.Key And ConversionKind.UserDefined) <> 0 AndAlso convKind.Value IsNot Nothing Then
                        errorTargetType = convKind.Value.Parameters(0).Type
                    Else
                        errorTargetType = targetType
                    End If

                    ReportDiagnostic(diagnostics, argument.Syntax, ERRID.ERR_ExpressionOverflow1, errorTargetType)

                ElseIf isExplicit OrElse Not MakeVarianceConversionSuggestion(convKind.Key, argument.Syntax, sourceType, targetType, diagnostics, justWarn:=False) Then
                    ReportNoConversionError(argument.Syntax, sourceType, targetType, diagnostics, copybackConversionParamName)
                End If

                Return New BoundConversion(tree, argument, convKind.Key And (Not ConversionKind.UserDefined), CheckOverflow, isExplicit, targetType, hasErrors:=True)
            End If

DoneWithDiagnostics:
            If (convKind.Key And ConversionKind.UserDefined) <> 0 Then
                Return CreateUserDefinedConversion(tree, argument, convKind, isExplicit, targetType, reportArrayLiteralElementNarrowingConversion, diagnostics)
            End If

            If argument.HasErrors OrElse (sourceType IsNot Nothing AndAlso sourceType.IsErrorType()) Then
                Return New BoundConversion(tree, argument, convKind.Key, CheckOverflow, isExplicit, targetType, hasErrors:=True)
            End If

            Return CreatePredefinedConversion(tree, argument, convKind.Key, isExplicit, targetType, diagnostics)
        End Function

        Private Structure VarianceSuggestionTypeParameterInfo
            Private _isViable As Boolean
            Private _typeParameter As TypeParameterSymbol
            Private _derivedArgument As TypeSymbol
            Private _baseArgument As TypeSymbol

            Public Sub [Set](parameter As TypeParameterSymbol, derived As TypeSymbol, base As TypeSymbol)
                _typeParameter = parameter
                _derivedArgument = derived
                _baseArgument = base
                _isViable = True
            End Sub

            Public ReadOnly Property IsViable As Boolean
                Get
                    Return _isViable
                End Get
            End Property

            Public ReadOnly Property TypeParameter As TypeParameterSymbol
                Get
                    Return _typeParameter
                End Get
            End Property

            Public ReadOnly Property DerivedArgument As TypeSymbol
                Get
                    Return _derivedArgument
                End Get
            End Property

            Public ReadOnly Property BaseArgument As TypeSymbol
                Get
                    Return _baseArgument
                End Get
            End Property
        End Structure

        ''' <summary>
        ''' Returns True if error or warning was reported.
        ''' 
        ''' This function is invoked on the occasion of a Narrowing or NoConversion.
        ''' It looks at the conversion. If the conversion could have been helped by variance in
        ''' some way, it reports an error/warning message to that effect and returns true. This
        ''' message is a substitute for whatever other conversion-failed message might have been displayed.
        '''
        ''' Note: these variance-related messages will NOT show auto-correct suggestion of using CType. That's
        ''' because, in these cases, it's more likely than not that CType will fail, so it would be a bad suggestion
        ''' </summary>
        Private Function MakeVarianceConversionSuggestion(
            convKind As ConversionKind,
            location As SyntaxNode,
            sourceType As TypeSymbol,
            targetType As TypeSymbol,
            diagnostics As BindingDiagnosticBag,
            justWarn As Boolean
        ) As Boolean
            Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics)
            Dim result As Boolean = MakeVarianceConversionSuggestion(convKind, location, sourceType, targetType, diagnostics, useSiteInfo, justWarn)
            diagnostics.AddDependencies(useSiteInfo)
            Return result
        End Function

        Private Function MakeVarianceConversionSuggestion(
            convKind As ConversionKind,
            location As SyntaxNode,
            sourceType As TypeSymbol,
            targetType As TypeSymbol,
            diagnostics As BindingDiagnosticBag,
            <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol),
            justWarn As Boolean
        ) As Boolean

            If (convKind And ConversionKind.UserDefined) <> 0 Then
                Return False
            End If

            ' Variance scenario 2: Dim x As List(Of Animal) = New List(Of Tiger)
            ' "List(Of Tiger) cannot be converted to List(Of Animal). Consider using IEnumerable(Of Animal) instead."
            '
            ' (1) If the user attempts a conversion to DEST which is a generic binding of one of the non-variant
            '     standard generic collection types List(Of D), Collection(Of D), ReadOnlyCollection(Of D),
            '     IList(Of D), ICollection(Of D)
            ' (2) and if the conversion failed (either ConversionNarrowing or ConversionError),
            ' (3) and if the source type SOURCE implemented/inherited exactly one binding ISOURCE=G(Of S) of that
            '     generic collection type G
            ' (4) and if there is a reference conversion from S to D
            ' (5) Then report "G(Of S) cannot be converted to G(Of D). Consider converting to IEnumerable(Of D) instead."

            If targetType.Kind <> SymbolKind.NamedType Then
                Return False
            End If

            Dim targetNamedType = DirectCast(targetType, NamedTypeSymbol)

            If Not targetNamedType.IsGenericType Then
                Return False
            End If

            Dim targetGenericDefinition As NamedTypeSymbol = targetNamedType.OriginalDefinition

            If targetGenericDefinition.SpecialType = SpecialType.System_Collections_Generic_IList_T OrElse
               targetGenericDefinition.SpecialType = SpecialType.System_Collections_Generic_ICollection_T OrElse
               targetGenericDefinition.SpecialType = SpecialType.System_Collections_Generic_IReadOnlyList_T OrElse
               targetGenericDefinition.SpecialType = SpecialType.System_Collections_Generic_IReadOnlyCollection_T OrElse
               targetGenericDefinition Is Compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_List_T) OrElse
               targetGenericDefinition Is Compilation.GetWellKnownType(WellKnownType.System_Collections_ObjectModel_Collection_T) OrElse
               targetGenericDefinition Is Compilation.GetWellKnownType(WellKnownType.System_Collections_ObjectModel_ReadOnlyCollection_T) Then

                Dim sourceTypeArgument As TypeSymbol = Nothing

                If targetGenericDefinition.IsInterfaceType() Then
                    Dim matchingInterfaces As New HashSet(Of NamedTypeSymbol)()
                    If IsOrInheritsFromOrImplementsInterface(sourceType, targetGenericDefinition, useSiteInfo:=useSiteInfo, matchingInterfaces:=matchingInterfaces) AndAlso
                        matchingInterfaces.Count = 1 Then
                        sourceTypeArgument = matchingInterfaces(0).TypeArgumentsNoUseSiteDiagnostics(0)
                    End If
                Else
                    Dim typeToCheck As TypeSymbol = sourceType

                    Do
                        If typeToCheck.OriginalDefinition Is targetGenericDefinition Then
                            sourceTypeArgument = DirectCast(typeToCheck, NamedTypeSymbol).TypeArgumentsNoUseSiteDiagnostics(0)
                            Exit Do
                        End If

                        typeToCheck = typeToCheck.BaseTypeNoUseSiteDiagnostics
                    Loop While typeToCheck IsNot Nothing
                End If

                If sourceTypeArgument IsNot Nothing AndAlso
                   Conversions.IsWideningConversion(Conversions.Classify_Reference_Array_TypeParameterConversion(sourceTypeArgument,
                                                                                                                 targetNamedType.TypeArgumentsNoUseSiteDiagnostics(0),
                                                                                                                 varianceCompatibilityClassificationDepth:=0,
                                                                                                                 useSiteInfo:=useSiteInfo)) Then
                    Dim iEnumerable_T As NamedTypeSymbol = Compilation.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T)

                    If Not iEnumerable_T.IsErrorType() Then
                        Dim suggestion As NamedTypeSymbol = iEnumerable_T.Construct(targetNamedType.TypeArgumentsNoUseSiteDiagnostics(0))

                        If justWarn Then
                            ReportDiagnostic(diagnostics, location, ERRID.WRN_ImplicitConversionSubst1,
                                             ErrorFactory.ErrorInfo(ERRID.WRN_VarianceIEnumerableSuggestion3, sourceType, targetType, suggestion))
                        Else
                            ReportDiagnostic(diagnostics, location, ERRID.ERR_VarianceIEnumerableSuggestion3, sourceType, targetType, suggestion)
                        End If

                        Return True
                    End If
                End If
            End If

            ' Variance scenario 1:                                  | Variance scenario 3:
            ' Dim x as IEnumerable(Of Tiger) = New List(Of Animal)  | Dim x As IGoo(Of Animal) = New MyGoo
            ' "List(Of Animal) cannot be converted to               | "MyGoo cannot be converted to IGoo(Of Animal).
            ' IEnumerable(Of Tiger) because 'Animal' is not derived | Consider changing the 'T' in the definition
            ' from 'Tiger', as required for the 'Out' generic       | of interface IGoo(Of T) to an Out type
            ' parameter 'T' in 'IEnumerable(Of Out T)'"             | parameter, Out T."
            '                                                       |
            ' (1) If the user attempts a conversion to              | (1) If the user attempts a conversion to some
            '     some target type DEST=G(Of D1,D2,...) which is    |     target type DEST=G(Of D1,D2,...) which is
            '     a generic instantiation of some variant interface/|     a generic instantiation of some interface/delegate
            '     delegate type G(Of T1,T2,...),                    |     type G(...), which NEED NOT be variant!
            ' (2) and if the conversion fails (Narrowing/Error),    | (2) and if the type G is defined in source-code,
            ' (3) and if the source type SOURCE implements/         |     not imported metadata. And the conversion fails.
            '     inherits exactly one binding INHSOURCE=           | (3) And INHSOURCE=exactly one binding of G
            '     G(Of S1,S2,...) of that generic type G,           | (4) And if ever difference is either Di/Si/Ti
            ' (4) and if the only differences between (D1,D2,...)   |     where Ti has In/Out variance, or is
            '     and (S1,S2,...) occur in positions "Di/Si"        |     Dj/Sj/Tj such that Tj has no variance and
            '     such that the corresponding Ti has either In      |     Dj has a CLR conversion to Sj or vice versa
            '     or Out variance                                   | (5) Then pick the first difference Dj/Sj
            ' (5) Then pick on the one such difference Si/Di/Ti     | (6) and report "SOURCE cannot be converted to
            ' (6) and report "SOURCE cannot be converted to DEST    |     DEST. Consider changing Tj in the definition
            '     because Si is not derived from Di, as required    |     of interface/delegate IGoo(Of T) to an
            '     for the 'In/Out' generic parameter 'T' in         |     In/Out type parameter, In/Out T".
            '     'IEnumerable(Of Out T)'"                          |
            Dim matchingGenericInstantiation As NamedTypeSymbol

            ' (1) If the user attempts a conversion 
            Select Case targetGenericDefinition.TypeKind
                Case TypeKind.Delegate
                    If sourceType.OriginalDefinition Is targetGenericDefinition Then
                        matchingGenericInstantiation = DirectCast(sourceType, NamedTypeSymbol)
                    Else
                        Return False
                    End If

                Case TypeKind.Interface
                    Dim matchingInterfaces As New HashSet(Of NamedTypeSymbol)()

                    If IsOrInheritsFromOrImplementsInterface(sourceType, targetGenericDefinition, useSiteInfo:=useSiteInfo, matchingInterfaces:=matchingInterfaces) AndAlso
                        matchingInterfaces.Count = 1 Then
                        matchingGenericInstantiation = matchingInterfaces(0)
                    Else
                        Return False
                    End If

                Case Else
                    Return False
            End Select

            ' (3) and if the source type implemented exactly one binding of it...
            Dim source As NamedTypeSymbol = matchingGenericInstantiation
            Dim destination As NamedTypeSymbol = targetNamedType

            Dim oneVariantDifference As VarianceSuggestionTypeParameterInfo = Nothing ' for Di/Si/Ti
            Dim oneInvariantConvertibleDifference As TypeParameterSymbol = Nothing 'for Dj/Sj/Tj where Sj<Dj
            Dim oneInvariantReverseConvertibleDifference As TypeParameterSymbol = Nothing ' Dj/Sj/Tj where Dj<Sj

            Do
                Dim typeParameters As ImmutableArray(Of TypeParameterSymbol) = source.TypeParameters
                Dim sourceArguments As ImmutableArray(Of TypeSymbol) = source.TypeArgumentsNoUseSiteDiagnostics
                Dim destinationArguments As ImmutableArray(Of TypeSymbol) = destination.TypeArgumentsNoUseSiteDiagnostics

                For i As Integer = 0 To typeParameters.Length - 1

                    Dim sourceArg As TypeSymbol = sourceArguments(i)
                    Dim destinationArg As TypeSymbol = destinationArguments(i)

                    If sourceArg.IsSameTypeIgnoringAll(destinationArg) Then
                        Continue For
                    End If

                    If sourceArg.IsErrorType() OrElse destinationArg.IsErrorType() Then
                        Continue For
                    End If

                    Dim conv As ConversionKind = Nothing

                    Select Case typeParameters(i).Variance
                        Case VarianceKind.Out
                            If sourceArg.IsValueType OrElse destinationArg.IsValueType Then
                                oneVariantDifference.Set(typeParameters(i), sourceArg, destinationArg)
                            Else
                                conv = Conversions.Classify_Reference_Array_TypeParameterConversion(sourceArg, destinationArg,
                                                                                                    varianceCompatibilityClassificationDepth:=0,
                                                                                                    useSiteInfo:=useSiteInfo)

                                If Not Conversions.IsWideningConversion(conv) Then
                                    If Not Conversions.IsNarrowingConversion(conv) OrElse (conv And ConversionKind.VarianceConversionAmbiguity) = 0 Then
                                        oneVariantDifference.Set(typeParameters(i), sourceArg, destinationArg)
                                    End If
                                End If
                            End If
                        Case VarianceKind.In
                            If sourceArg.IsValueType OrElse destinationArg.IsValueType Then
                                oneVariantDifference.Set(typeParameters(i), destinationArg, sourceArg)
                            Else
                                conv = Conversions.Classify_Reference_Array_TypeParameterConversion(destinationArg, sourceArg,
                                                                                                    varianceCompatibilityClassificationDepth:=0,
                                                                                                    useSiteInfo:=useSiteInfo)

                                If Not Conversions.IsWideningConversion(conv) Then
                                    If (targetNamedType.IsDelegateType AndAlso destinationArg.IsReferenceType AndAlso sourceArg.IsReferenceType) OrElse
                                       Not Conversions.IsNarrowingConversion(conv) OrElse
                                       (conv And ConversionKind.VarianceConversionAmbiguity) = 0 Then
                                        oneVariantDifference.Set(typeParameters(i), destinationArg, sourceArg)
                                    End If
                                End If
                            End If

                        Case Else
                            conv = Conversions.ClassifyDirectCastConversion(sourceArg, destinationArg, useSiteInfo)

                            If Conversions.IsWideningConversion(conv) Then
                                oneInvariantConvertibleDifference = typeParameters(i)
                            Else
                                conv = Conversions.ClassifyDirectCastConversion(destinationArg, sourceArg, useSiteInfo)

                                If Conversions.IsWideningConversion(conv) Then
                                    oneInvariantReverseConvertibleDifference = typeParameters(i)
                                Else
                                    Return False
                                End If
                            End If
                    End Select

                Next

                source = source.ContainingType
                destination = destination.ContainingType
            Loop While source IsNot Nothing

            ' (5) If a Di/Si/Ti, and no Dj/Sj/Tj nor Dk/Sk/Tk, then report...
            If oneVariantDifference.IsViable AndAlso
               oneInvariantConvertibleDifference Is Nothing AndAlso
               oneInvariantReverseConvertibleDifference Is Nothing Then

                Dim containerFormatter As FormattedSymbol

                If oneVariantDifference.TypeParameter.ContainingType.IsDelegateType Then
                    containerFormatter = CustomSymbolDisplayFormatter.DelegateSignature(oneVariantDifference.TypeParameter.ContainingSymbol)
                Else
                    containerFormatter = CustomSymbolDisplayFormatter.ErrorNameWithKind(oneVariantDifference.TypeParameter.ContainingSymbol)
                End If

                If justWarn Then
                    ReportDiagnostic(diagnostics, location, ERRID.WRN_ImplicitConversionSubst1,
                                     ErrorFactory.ErrorInfo(If(oneVariantDifference.TypeParameter.Variance = VarianceKind.Out,
                                                               ERRID.WRN_VarianceConversionFailedOut6,
                                                               ERRID.WRN_VarianceConversionFailedIn6),
                                                            oneVariantDifference.DerivedArgument,
                                                            oneVariantDifference.BaseArgument,
                                                            oneVariantDifference.TypeParameter.Name,
                                                            containerFormatter,
                                                            sourceType,
                                                            targetType))
                Else
                    ReportDiagnostic(diagnostics, location, If(oneVariantDifference.TypeParameter.Variance = VarianceKind.Out,
                                                               ERRID.ERR_VarianceConversionFailedOut6,
                                                               ERRID.ERR_VarianceConversionFailedIn6),
                                                            oneVariantDifference.DerivedArgument,
                                                            oneVariantDifference.BaseArgument,
                                                            oneVariantDifference.TypeParameter.Name,
                                                            containerFormatter,
                                                            sourceType,
                                                            targetType)
                End If

                Return True
            End If

            ' (5b) Otherwise, if a Dj/Sj/Tj and no Dk/Sk/Tk, and G came not from metadata, then report...
            If (oneInvariantConvertibleDifference IsNot Nothing OrElse oneInvariantReverseConvertibleDifference IsNot Nothing) AndAlso
                targetType.ContainingModule Is Compilation.SourceModule Then

                Dim oneInvariantDifference As TypeParameterSymbol

                If oneInvariantConvertibleDifference IsNot Nothing Then
                    oneInvariantDifference = oneInvariantConvertibleDifference
                Else
                    oneInvariantDifference = oneInvariantReverseConvertibleDifference
                End If

                Dim containerFormatter As FormattedSymbol

                If oneInvariantDifference.ContainingType.IsDelegateType Then
                    containerFormatter = CustomSymbolDisplayFormatter.DelegateSignature(oneInvariantDifference.ContainingSymbol)
                Else
                    containerFormatter = CustomSymbolDisplayFormatter.ErrorNameWithKind(oneInvariantDifference.ContainingSymbol)
                End If

                If justWarn Then
                    ReportDiagnostic(diagnostics, location, ERRID.WRN_ImplicitConversionSubst1,
                                     ErrorFactory.ErrorInfo(If(oneInvariantConvertibleDifference IsNot Nothing,
                                                               ERRID.WRN_VarianceConversionFailedTryOut4,
                                                               ERRID.WRN_VarianceConversionFailedTryIn4),
                                                            sourceType,
                                                            targetType,
                                                            oneInvariantDifference.Name,
                                                            containerFormatter))
                Else
                    ReportDiagnostic(diagnostics, location, If(oneInvariantConvertibleDifference IsNot Nothing,
                                                               ERRID.ERR_VarianceConversionFailedTryOut4,
                                                               ERRID.ERR_VarianceConversionFailedTryIn4),
                                                            sourceType,
                                                            targetType,
                                                            oneInvariantDifference.Name,
                                                            containerFormatter)
                End If

                Return True
            End If

            Return False
        End Function

        Private Function CreatePredefinedConversion(
            tree As SyntaxNode,
            argument As BoundExpression,
            convKind As ConversionKind,
            isExplicit As Boolean,
            targetType As TypeSymbol,
            diagnostics As BindingDiagnosticBag
        ) As BoundConversion
            Debug.Assert(Conversions.ConversionExists(convKind) AndAlso (convKind And ConversionKind.UserDefined) = 0)

            Dim sourceType = argument.Type

            ' Handle Anonymous Delegate conversion.
            If (convKind And ConversionKind.AnonymousDelegate) <> 0 Then

                ' Don't spend time building a narrowing relaxation stub if we already complained about the narrowing.
                If isExplicit OrElse OptionStrict <> VisualBasic.OptionStrict.On OrElse Conversions.IsWideningConversion(convKind) Then
                    Debug.Assert(Not Conversions.IsIdentityConversion(convKind))
                    Debug.Assert(sourceType.IsDelegateType() AndAlso DirectCast(sourceType, NamedTypeSymbol).IsAnonymousType AndAlso targetType.IsDelegateType() AndAlso
                                 targetType.SpecialType <> SpecialType.System_MulticastDelegate)

                    Dim boundLambdaOpt As BoundLambda = Nothing
                    Dim relaxationReceiverPlaceholderOpt As BoundRValuePlaceholder = Nothing
                    Dim methodToConvert As MethodSymbol = DirectCast(sourceType, NamedTypeSymbol).DelegateInvokeMethod

                    If (convKind And ConversionKind.NeedAStub) <> 0 Then
                        Dim relaxationBinder As Binder

                        ' If conversion is explicit, use Option Strict Off.
                        If isExplicit AndAlso Me.OptionStrict <> VisualBasic.OptionStrict.Off Then
                            relaxationBinder = New OptionStrictOffBinder(Me)
                        Else
                            relaxationBinder = Me
                        End If

                        Debug.Assert(Not isExplicit OrElse relaxationBinder.OptionStrict = VisualBasic.OptionStrict.Off)

                        boundLambdaOpt = relaxationBinder.BuildDelegateRelaxationLambda(tree, tree, argument, methodToConvert,
                                                                                        Nothing, QualificationKind.QualifiedViaValue,
                                                                                        DirectCast(targetType, NamedTypeSymbol).DelegateInvokeMethod,
                                                                                        convKind And ConversionKind.DelegateRelaxationLevelMask,
                                                                                        isZeroArgumentKnownToBeUsed:=False,
                                                                                        warnIfResultOfAsyncMethodIsDroppedDueToRelaxation:=False,
                                                                                        diagnostics:=diagnostics,
                                                                                        relaxationReceiverPlaceholder:=relaxationReceiverPlaceholderOpt)
                    End If

                    ' The conversion has the lambda stored internally to not clutter the bound tree with synthesized nodes 
                    ' in the first pass. Later the node get's rewritten into a delegate creation with the lambda if needed.
                    Return New BoundConversion(tree, argument, convKind, False, isExplicit, Nothing,
                                               If(boundLambdaOpt Is Nothing,
                                                  Nothing,
                                                  New BoundRelaxationLambda(tree, boundLambdaOpt, relaxationReceiverPlaceholderOpt).MakeCompilerGenerated()),
                                               targetType)
                Else
                    Debug.Assert(Not diagnostics.AccumulatesDiagnostics OrElse diagnostics.HasAnyErrors())
                End If
            End If

            Dim integerOverflow As Boolean = False

            Dim constantResult = Conversions.TryFoldConstantConversion(
                                    argument,
                                    targetType,
                                    integerOverflow)

            If constantResult IsNot Nothing Then
                ' Overflow should have been detected at classification time.
                Debug.Assert(Not integerOverflow OrElse Not CheckOverflow)
                Debug.Assert(Not constantResult.IsBad)
            Else
                constantResult = Conversions.TryFoldNothingReferenceConversion(argument, convKind, targetType)
            End If

            Dim tupleElements As BoundConvertedTupleElements = CreateConversionForTupleElements(tree, sourceType, targetType, convKind, isExplicit)

            If (convKind = ConversionKind.WideningReference OrElse convKind = ConversionKind.NarrowingReference) AndAlso
                sourceType.IsWellKnownTypeLock() Then
                ReportDiagnostic(diagnostics, argument.Syntax, ERRID.WRN_ConvertingLock)
            End If

            Return New BoundConversion(tree, argument, convKind, CheckOverflow, isExplicit, constantResult, tupleElements, targetType)
        End Function

        Private Function CreateConversionForTupleElements(
            tree As SyntaxNode,
            sourceType As TypeSymbol,
            targetType As TypeSymbol,
            convKind As ConversionKind,
            isExplicit As Boolean
        ) As BoundConvertedTupleElements

            If (convKind And ConversionKind.Tuple) <> 0 Then
                Dim sourceElementTypes = sourceType.GetNullableUnderlyingTypeOrSelf().GetElementTypesOfTupleOrCompatible()
                Dim targetElementTypes = targetType.GetNullableUnderlyingTypeOrSelf().GetElementTypesOfTupleOrCompatible()

                Dim placeholders = ArrayBuilder(Of BoundRValuePlaceholder).GetInstance(sourceElementTypes.Length)
                Dim converted = ArrayBuilder(Of BoundExpression).GetInstance(sourceElementTypes.Length)

                For i As Integer = 0 To sourceElementTypes.Length - 1
                    Dim placeholder = New BoundRValuePlaceholder(tree, sourceElementTypes(i)).MakeCompilerGenerated()
                    placeholders.Add(placeholder)
                    converted.Add(ApplyConversion(tree, targetElementTypes(i), placeholder, isExplicit, BindingDiagnosticBag.Discarded))
                Next

                Return New BoundConvertedTupleElements(tree, placeholders.ToImmutableAndFree(), converted.ToImmutableAndFree()).MakeCompilerGenerated()
            End If

            Return Nothing
        End Function

        Private Function CreateUserDefinedConversion(
            tree As SyntaxNode,
            argument As BoundExpression,
            convKind As KeyValuePair(Of ConversionKind, MethodSymbol),
            isExplicit As Boolean,
            targetType As TypeSymbol,
            reportArrayLiteralElementNarrowingConversion As Boolean,
            diagnostics As BindingDiagnosticBag
        ) As BoundConversion
            Debug.Assert((convKind.Key And ConversionKind.UserDefined) <> 0 AndAlso convKind.Value IsNot Nothing AndAlso
                         convKind.Value.ParameterCount = 1 AndAlso Not convKind.Value.IsSub AndAlso
                         Not convKind.Value.Parameters(0).IsByRef AndAlso convKind.Value.IsShared)

            ' Suppress any Option Strict diagnostics.
            Dim conversionBinder = New OptionStrictOffBinder(Me)

            Dim argumentSyntax = argument.Syntax
            Dim originalArgumentType As TypeSymbol = argument.Type
            Dim inType As TypeSymbol = convKind.Value.Parameters(0).Type
            Dim outType As TypeSymbol = convKind.Value.ReturnType

            Dim intermediateConv As ConversionKind
            Dim inOutConversionFlags As Byte = 0
            Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics)

            If argument.Kind = BoundKind.ArrayLiteral Then
                ' For array literals, report Option Strict diagnostics for each element when reportArrayLiteralElementNarrowingConversion is true.
                Dim arrayLiteral = DirectCast(argument, BoundArrayLiteral)
                Dim arrayLiteralBinder = If(reportArrayLiteralElementNarrowingConversion, Me, conversionBinder)
                intermediateConv = Conversions.ClassifyArrayLiteralConversion(arrayLiteral, inType, arrayLiteralBinder, useSiteInfo)

                argument = arrayLiteralBinder.ReclassifyArrayLiteralExpression(SyntaxKind.CTypeKeyword, tree,
                                                            intermediateConv,
                                                            isExplicit,
                                                            arrayLiteral,
                                                            inType, diagnostics)
                originalArgumentType = inType
            Else
                intermediateConv = Conversions.ClassifyPredefinedConversion(argument, inType, conversionBinder, useSiteInfo)

                If Not Conversions.IsIdentityConversion(intermediateConv) Then
#If DEBUG Then
                    Dim oldArgument = argument
#End If
                    argument = conversionBinder.CreatePredefinedConversion(tree, argument, intermediateConv, isExplicit, inType, diagnostics).
                                                MakeCompilerGenerated()
#If DEBUG Then
                    Debug.Assert(oldArgument IsNot argument AndAlso argument.Kind = BoundKind.Conversion)
#End If
                    inOutConversionFlags = 1
                End If
            End If

            ReportUseSite(diagnostics, tree, convKind.Value)

            ReportDiagnosticsIfObsoleteOrNotSupported(diagnostics, convKind.Value, tree)

            Debug.Assert(convKind.Value.IsUserDefinedOperator())
            If Me.ContainingMember Is convKind.Value Then
                ReportDiagnostic(diagnostics, argumentSyntax, ERRID.WRN_RecursiveOperatorCall, convKind.Value)
            End If

            argument = New BoundCall(tree,
                                     method:=convKind.Value,
                                     methodGroupOpt:=Nothing,
                                     receiverOpt:=Nothing,
                                     arguments:=ImmutableArray.Create(Of BoundExpression)(argument),
                                     constantValueOpt:=Nothing,
                                     suppressObjectClone:=True,
                                     type:=outType).MakeCompilerGenerated()

            intermediateConv = Conversions.ClassifyPredefinedConversion(argument, targetType, conversionBinder, useSiteInfo)

            If Not Conversions.IsIdentityConversion(intermediateConv) Then
#If DEBUG Then
                Dim oldArgument = argument
#End If
                argument = conversionBinder.CreatePredefinedConversion(tree, argument, intermediateConv, isExplicit, targetType, diagnostics).
                                            MakeCompilerGenerated()
#If DEBUG Then
                Debug.Assert(oldArgument IsNot argument AndAlso argument.Kind = BoundKind.Conversion)
#End If
                inOutConversionFlags = inOutConversionFlags Or CByte(2)
            End If

            argument = New BoundUserDefinedConversion(tree, argument, inOutConversionFlags, originalArgumentType).MakeCompilerGenerated()

            diagnostics.Add(tree, useSiteInfo)
            Return New BoundConversion(tree, argument, convKind.Key, CheckOverflow, isExplicit, DirectCast(Nothing, ConstantValue), targetType)
        End Function

        ''' <summary>
        ''' Handle expression reclassification, if any applicable.
        ''' 
        ''' If function returns True, the "argument" parameter has been replaced
        ''' with result of reclassification (possibly an error node) and appropriate
        ''' diagnostic, if any, has been reported.
        ''' 
        ''' If function returns false, the "argument" parameter must be unchanged and no 
        ''' diagnostic should be reported. 
        ''' 
        ''' conversionSemantics can be one of these: 
        '''       SyntaxKind.CTypeKeyword, SyntaxKind.DirectCastKeyword, SyntaxKind.TryCastKeyword
        ''' </summary>
        Private Function ReclassifyExpression(
            ByRef argument As BoundExpression,
            conversionSemantics As SyntaxKind,
            tree As SyntaxNode,
            convKind As ConversionKind,
            isExplicit As Boolean,
            targetType As TypeSymbol,
            diagnostics As BindingDiagnosticBag
        ) As Boolean
            Debug.Assert(argument.Kind <> BoundKind.GroupTypeInferenceLambda)

            Select Case argument.Kind
                Case BoundKind.Parenthesized
                    If argument.Type Is Nothing AndAlso Not argument.IsNothingLiteral() Then
                        Dim parenthesized = DirectCast(argument, BoundParenthesized)
                        Dim enclosed As BoundExpression = parenthesized.Expression

                        ' Reclassify enclosed expression.
                        If ReclassifyExpression(enclosed, conversionSemantics, enclosed.Syntax, convKind, isExplicit, targetType, diagnostics) Then
                            argument = parenthesized.Update(enclosed, enclosed.Type)

                            Return True
                        End If
                    End If

                Case BoundKind.UnboundLambda
                    argument = ReclassifyUnboundLambdaExpression(DirectCast(argument, UnboundLambda), conversionSemantics, tree,
                                                                 convKind, isExplicit, targetType, diagnostics)
                    Return True

                Case BoundKind.QueryLambda

                    argument = ReclassifyQueryLambdaExpression(DirectCast(argument, BoundQueryLambda), conversionSemantics, tree,
                                                                 convKind, isExplicit, targetType, diagnostics)
                    Return True

                Case BoundKind.LateAddressOfOperator
                    Dim addressOfExpression = DirectCast(argument, BoundLateAddressOfOperator)

                    If targetType.TypeKind <> TypeKind.Delegate AndAlso targetType.TypeKind <> TypeKind.Error Then
                        ' 'AddressOf' expression cannot be converted to '{0}' because '{0}' is not a delegate type.
                        ReportDiagnostic(diagnostics, addressOfExpression.Syntax, ERRID.ERR_AddressOfNotDelegate1, targetType)
                    End If

                    argument = addressOfExpression.Update(addressOfExpression.Binder, addressOfExpression.MemberAccess, targetType)
                    Return True

                Case BoundKind.AddressOfOperator
                    Dim delegateResolutionResult As DelegateResolutionResult = Nothing
                    Dim addressOfExpression = DirectCast(argument, BoundAddressOfOperator)
                    If addressOfExpression.GetDelegateResolutionResult(targetType, delegateResolutionResult) Then

                        diagnostics.AddRange(delegateResolutionResult.Diagnostics)
                        Dim hasErrors = True

                        If Conversions.ConversionExists(delegateResolutionResult.DelegateConversions) Then
                            Dim reclassifyBinder As Binder

                            ' If conversion is explicit, use Option Strict Off.
                            If isExplicit AndAlso Me.OptionStrict <> VisualBasic.OptionStrict.Off Then
                                reclassifyBinder = New OptionStrictOffBinder(Me)
                            Else
                                reclassifyBinder = Me
                            End If

                            Debug.Assert(Not isExplicit OrElse reclassifyBinder.OptionStrict = VisualBasic.OptionStrict.Off)

                            argument = reclassifyBinder.ReclassifyAddressOf(addressOfExpression, delegateResolutionResult, targetType, diagnostics, isForHandles:=False,
                                                                            warnIfResultOfAsyncMethodIsDroppedDueToRelaxation:=Not isExplicit AndAlso tree.Kind <> SyntaxKind.ObjectCreationExpression)
                            hasErrors = argument.HasErrors

                            Debug.Assert(convKind = delegateResolutionResult.DelegateConversions)
                        End If

                        If argument.Kind <> BoundKind.DelegateCreationExpression Then
                            If conversionSemantics = SyntaxKind.CTypeKeyword Then
                                argument = New BoundConversion(tree, argument, convKind, False, isExplicit, targetType, hasErrors:=hasErrors)
                            ElseIf conversionSemantics = SyntaxKind.DirectCastKeyword Then
                                argument = New BoundDirectCast(tree, argument, convKind, targetType, hasErrors:=hasErrors)
                            ElseIf conversionSemantics = SyntaxKind.TryCastKeyword Then
                                argument = New BoundTryCast(tree, argument, convKind, targetType, hasErrors:=hasErrors)
                            Else
                                Throw ExceptionUtilities.UnexpectedValue(conversionSemantics)
                            End If
                        End If

                        Return True
                    End If

                Case BoundKind.ArrayLiteral
                    argument = ReclassifyArrayLiteralExpression(conversionSemantics, tree, convKind, isExplicit, DirectCast(argument, BoundArrayLiteral), targetType, diagnostics)
                    Return True

                Case BoundKind.InterpolatedStringExpression

                    argument = ReclassifyInterpolatedStringExpression(conversionSemantics, tree, convKind, isExplicit, DirectCast(argument, BoundInterpolatedStringExpression), targetType, diagnostics)
                    Return argument.Kind = BoundKind.Conversion

                Case BoundKind.TupleLiteral
                    Dim literal = DirectCast(argument, BoundTupleLiteral)
                    argument = ReclassifyTupleLiteral(convKind, tree, isExplicit, literal, targetType, diagnostics)

                    Return argument IsNot literal

            End Select

            Return False
        End Function

        Private Function ReclassifyUnboundLambdaExpression(
            unboundLambda As UnboundLambda,
            conversionSemantics As SyntaxKind,
            tree As SyntaxNode,
            convKind As ConversionKind,
            isExplicit As Boolean,
            targetType As TypeSymbol,
            diagnostics As BindingDiagnosticBag
        ) As BoundExpression

            Dim targetDelegateType As NamedTypeSymbol ' the target delegate type; if targetType is Expression(Of D), then this is D, otherwise targetType or Nothing.
            Dim delegateInvoke As MethodSymbol

            If targetType.IsStrictSupertypeOfConcreteDelegate() Then ' covers Object, System.Delegate, System.MulticastDelegate
                ' Reclassify the lambda as an instance of an Anonymous Delegate.
                Dim anonymousDelegate As BoundExpression = ReclassifyUnboundLambdaExpression(unboundLambda, diagnostics)

#If DEBUG Then
                Dim anonymousDelegateInfo As KeyValuePair(Of NamedTypeSymbol, ReadOnlyBindingDiagnostic(Of AssemblySymbol)) = unboundLambda.InferredAnonymousDelegate

                Debug.Assert(anonymousDelegate.Type Is anonymousDelegateInfo.Key)

                ' If we have errors for the inference, we know that there is no conversion.
                If Not anonymousDelegateInfo.Value.Diagnostics.IsDefault AndAlso anonymousDelegateInfo.Value.Diagnostics.HasAnyErrors() Then
                    Debug.Assert(Conversions.NoConversion(convKind) AndAlso (convKind And ConversionKind.DelegateRelaxationLevelMask) = 0)
                Else
                    Debug.Assert(Conversions.NoConversion(convKind) OrElse
                             (convKind And ConversionKind.DelegateRelaxationLevelMask) >= ConversionKind.DelegateRelaxationLevelWideningToNonLambda)
                End If
#End If
                ' Now convert it to the target type.
                If conversionSemantics = SyntaxKind.CTypeKeyword Then
                    Return ApplyConversion(tree, targetType, anonymousDelegate, isExplicit, diagnostics)
                ElseIf conversionSemantics = SyntaxKind.DirectCastKeyword Then
                    Return ApplyDirectCastConversion(tree, anonymousDelegate, targetType, diagnostics)
                ElseIf conversionSemantics = SyntaxKind.TryCastKeyword Then
                    Return ApplyTryCastConversion(tree, anonymousDelegate, targetType, diagnostics)
                Else
                    Throw ExceptionUtilities.UnexpectedValue(conversionSemantics)
                End If
            Else
                targetDelegateType = targetType.DelegateOrExpressionDelegate(Me)

                If targetDelegateType Is Nothing Then
                    Debug.Assert((convKind And ConversionKind.DelegateRelaxationLevelMask) = 0)
                    ReportDiagnostic(diagnostics, unboundLambda.Syntax, ERRID.ERR_LambdaNotDelegate1, targetType)
                    delegateInvoke = Nothing ' No conversion
                Else
                    delegateInvoke = targetDelegateType.DelegateInvokeMethod

                    If delegateInvoke Is Nothing Then
                        ReportDiagnostic(diagnostics, unboundLambda.Syntax, ERRID.ERR_LambdaNotDelegate1, targetDelegateType)
                        delegateInvoke = Nothing ' No conversion
                    ElseIf ReportDelegateInvokeUseSite(diagnostics, unboundLambda.Syntax, targetDelegateType, delegateInvoke) Then
                        delegateInvoke = Nothing ' No conversion

                    ElseIf unboundLambda.IsInferredDelegateForThisLambda(delegateInvoke.ContainingType) Then
                        Dim inferenceDiagnostics As ReadOnlyBindingDiagnostic(Of AssemblySymbol) = unboundLambda.InferredAnonymousDelegate.Value

                        diagnostics.AddRange(inferenceDiagnostics)

                        If Not inferenceDiagnostics.Diagnostics.IsDefaultOrEmpty AndAlso inferenceDiagnostics.Diagnostics.HasAnyErrors() Then
                            delegateInvoke = Nothing ' No conversion
                        End If
                    End If

                    Debug.Assert(delegateInvoke IsNot Nothing OrElse (convKind And ConversionKind.DelegateRelaxationLevelMask) = 0)
                End If
            End If

            Dim boundLambda As BoundLambda = Nothing

            If delegateInvoke IsNot Nothing Then
                boundLambda = unboundLambda.GetBoundLambda(New UnboundLambda.TargetSignature(delegateInvoke))

                Debug.Assert(boundLambda IsNot Nothing)
                If boundLambda Is Nothing Then
                    ' An unlikely case.
                    Debug.Assert((convKind And ConversionKind.DelegateRelaxationLevelMask) = 0)
                    ReportDiagnostic(diagnostics,
                                     unboundLambda.Syntax,
                                     If(unboundLambda.IsFunctionLambda, ERRID.ERR_LambdaBindingMismatch1, ERRID.ERR_LambdaBindingMismatch2),
                                     If(targetDelegateType.TypeKind = TypeKind.Delegate AndAlso targetDelegateType.IsFromCompilation(Me.Compilation),
                                        CType(CustomSymbolDisplayFormatter.DelegateSignature(targetDelegateType), Object),
                                        CType(targetDelegateType, Object)))
                End If
            End If

            If boundLambda Is Nothing Then
                Debug.Assert(Conversions.NoConversion(convKind))

                Dim errorRecovery As BoundLambda = unboundLambda.BindForErrorRecovery()

                If conversionSemantics = SyntaxKind.CTypeKeyword Then
                    Return New BoundConversion(tree, errorRecovery, convKind, False, isExplicit, targetType, hasErrors:=True)
                ElseIf conversionSemantics = SyntaxKind.DirectCastKeyword Then
                    Return New BoundDirectCast(tree, errorRecovery, convKind, targetType, hasErrors:=True)
                ElseIf conversionSemantics = SyntaxKind.TryCastKeyword Then
                    Return New BoundTryCast(tree, errorRecovery, convKind, targetType, hasErrors:=True)
                Else
                    Throw ExceptionUtilities.UnexpectedValue(conversionSemantics)
                End If
            End If

            Dim boundLambdaDiagnostics = boundLambda.Diagnostics

            Debug.Assert((convKind And ConversionKind.DelegateRelaxationLevelMask) >= boundLambda.DelegateRelaxation)
            Debug.Assert(Conversions.ClassifyMethodConversionForLambdaOrAnonymousDelegate(delegateInvoke, boundLambda.LambdaSymbol, CompoundUseSiteInfo(Of AssemblySymbol).Discarded) = MethodConversionKind.Identity OrElse
                         ((convKind And ConversionKind.DelegateRelaxationLevelMask) <> ConversionKind.DelegateRelaxationLevelNone AndAlso
                          boundLambda.MethodConversionKind <> MethodConversionKind.Identity))

            Dim reportedAnError As Boolean = boundLambdaDiagnostics.Diagnostics.HasAnyErrors()

            diagnostics.AddRange(boundLambdaDiagnostics)

            Dim relaxationLambdaOpt As BoundLambda = Nothing

            If (convKind And ConversionKind.DelegateRelaxationLevelMask) = ConversionKind.DelegateRelaxationLevelInvalid AndAlso
                Not reportedAnError AndAlso Not boundLambda.HasErrors Then

                ' We don't try to infer return type of a lambda that has both Async and Iterator modifiers, let's suppress the 
                ' signature mismatch error in this case.
                If unboundLambda.ReturnType IsNot Nothing OrElse unboundLambda.Flags <> (SourceMemberFlags.Async Or SourceMemberFlags.Iterator) Then
                    Dim err As ERRID

                    If unboundLambda.IsFunctionLambda Then
                        err = ERRID.ERR_LambdaBindingMismatch1
                    Else
                        err = ERRID.ERR_LambdaBindingMismatch2
                    End If

                    ReportDiagnostic(diagnostics,
                                     unboundLambda.Syntax,
                                     err,
                                     If(targetDelegateType.TypeKind = TypeKind.Delegate AndAlso targetDelegateType.IsFromCompilation(Me.Compilation),
                                        CType(CustomSymbolDisplayFormatter.DelegateSignature(targetDelegateType), Object),
                                        CType(targetDelegateType, Object)))
                End If
            ElseIf Conversions.IsStubRequiredForMethodConversion(boundLambda.MethodConversionKind) Then
                Debug.Assert(Conversions.IsDelegateRelaxationSupportedFor(boundLambda.MethodConversionKind))

                ' Need to produce a stub.

                ' First, we need to get an Anonymous Delegate of the same shape as the lambdaSymbol.
                Dim lambdaSymbol As LambdaSymbol = boundLambda.LambdaSymbol
                Dim anonymousDelegateType As NamedTypeSymbol = ConstructAnonymousDelegateSymbol(unboundLambda,
                                                                                       (lambdaSymbol.Parameters.As(Of BoundLambdaParameterSymbol)),
                                                                                       lambdaSymbol.ReturnType,
                                                                                       diagnostics)

                ' Second, reclassify the bound lambda as an instance of the Anonymous Delegate.
                Dim anonymousDelegateInstance = New BoundConversion(tree, boundLambda, ConversionKind.Widening Or ConversionKind.Lambda,
                                                                    False, False, anonymousDelegateType)
                anonymousDelegateInstance.SetWasCompilerGenerated()

                ' Third, create a method group representing Invoke method of the instance of the Anonymous Delegate.
                Dim methodGroup = New BoundMethodGroup(unboundLambda.Syntax,
                                                       Nothing,
                                                       ImmutableArray.Create(anonymousDelegateType.DelegateInvokeMethod),
                                                       LookupResultKind.Good,
                                                       anonymousDelegateInstance,
                                                       QualificationKind.QualifiedViaValue)
                methodGroup.SetWasCompilerGenerated()

                ' Fourth, create a lambda with the shape of the target delegate that calls the Invoke with appropriate conversions
                ' and drops parameters and/or return value, if needed, thus performing the relaxation.

                Dim relaxationBinder As Binder

                ' If conversion is explicit, use Option Strict Off.
                If isExplicit AndAlso Me.OptionStrict <> VisualBasic.OptionStrict.Off Then
                    relaxationBinder = New OptionStrictOffBinder(Me)
                Else
                    relaxationBinder = Me
                End If

                Debug.Assert(Not isExplicit OrElse relaxationBinder.OptionStrict = VisualBasic.OptionStrict.Off)

                relaxationLambdaOpt = relaxationBinder.BuildDelegateRelaxationLambda(unboundLambda.Syntax,
                                                                                     delegateInvoke,
                                                                                     methodGroup,
                                                                                     boundLambda.DelegateRelaxation,
                                                                                     isZeroArgumentKnownToBeUsed:=False,
                                                                                     warnIfResultOfAsyncMethodIsDroppedDueToRelaxation:=Not isExplicit AndAlso tree.Kind <> SyntaxKind.ObjectCreationExpression,
                                                                                     diagnostics:=diagnostics)
            End If

            If conversionSemantics = SyntaxKind.CTypeKeyword Then
                Return New BoundConversion(tree, boundLambda, convKind, False, isExplicit, Nothing,
                                           If(relaxationLambdaOpt Is Nothing,
                                              Nothing,
                                              New BoundRelaxationLambda(tree, relaxationLambdaOpt, receiverPlaceholderOpt:=Nothing).MakeCompilerGenerated()),
                                           targetType)
            ElseIf conversionSemantics = SyntaxKind.DirectCastKeyword Then
                Return New BoundDirectCast(tree, boundLambda, convKind, relaxationLambdaOpt, targetType)
            ElseIf conversionSemantics = SyntaxKind.TryCastKeyword Then
                Return New BoundTryCast(tree, boundLambda, convKind, relaxationLambdaOpt, targetType)
            Else
                Throw ExceptionUtilities.UnexpectedValue(conversionSemantics)
            End If
        End Function

        Private Function ReclassifyQueryLambdaExpression(
            lambda As BoundQueryLambda,
            conversionSemantics As SyntaxKind,
            tree As SyntaxNode,
            convKind As ConversionKind,
            isExplicit As Boolean,
            targetType As TypeSymbol,
            diagnostics As BindingDiagnosticBag
        ) As BoundExpression
            Debug.Assert(lambda.Type Is Nothing)

            ' the target delegate type; if targetType is Expression(Of D), then this is D, otherwise targetType or Nothing.
            Dim targetDelegateType As NamedTypeSymbol = targetType.DelegateOrExpressionDelegate(Me)

            If Conversions.NoConversion(convKind) Then

                If targetType.IsStrictSupertypeOfConcreteDelegate() AndAlso Not targetType.IsObjectType() Then
                    ReportDiagnostic(diagnostics, lambda.Syntax, ERRID.ERR_LambdaNotCreatableDelegate1, targetType)
                Else
                    If targetDelegateType Is Nothing Then
                        ReportDiagnostic(diagnostics, lambda.Syntax, ERRID.ERR_LambdaNotDelegate1, targetType)
                    Else
                        Dim invoke As MethodSymbol = targetDelegateType.DelegateInvokeMethod

                        If invoke Is Nothing Then
                            ReportDiagnostic(diagnostics, lambda.Syntax, ERRID.ERR_LambdaNotDelegate1, targetDelegateType)
                        ElseIf Not ReportDelegateInvokeUseSite(diagnostics, lambda.Syntax, targetDelegateType, invoke) Then

                            ' Conversion could fail because we couldn't convert body of the lambda
                            ' to the target delegate type. We want to report that error instead of
                            ' lambda signature mismatch.
                            If lambda.LambdaSymbol.ReturnType Is LambdaSymbol.ReturnTypePendingDelegate AndAlso
                               Not invoke.IsSub AndAlso
                               Conversions.FailedDueToQueryLambdaBodyMismatch(convKind) Then

                                lambda = lambda.Update(lambda.LambdaSymbol, lambda.RangeVariables,
                                                       ApplyImplicitConversion(lambda.Expression.Syntax,
                                                                               invoke.ReturnType,
                                                                               lambda.Expression,
                                                                               diagnostics,
                                                                               If(invoke.ReturnType.IsBooleanType,
                                                                                  lambda.ExprIsOperandOfConditionalBranch,
                                                                                  False)),
                                                       exprIsOperandOfConditionalBranch:=False)

                            Else
                                ReportDiagnostic(diagnostics, lambda.Syntax, ERRID.ERR_LambdaBindingMismatch1, targetDelegateType)
                            End If
                        End If
                    End If
                End If

                If conversionSemantics = SyntaxKind.CTypeKeyword Then
                    Return New BoundConversion(tree, lambda, convKind, False, isExplicit, targetType, hasErrors:=True).MakeCompilerGenerated()
                ElseIf conversionSemantics = SyntaxKind.DirectCastKeyword Then
                    Return New BoundDirectCast(tree, lambda, convKind, targetType, hasErrors:=True).MakeCompilerGenerated()
                ElseIf conversionSemantics = SyntaxKind.TryCastKeyword Then
                    Return New BoundTryCast(tree, lambda, convKind, targetType, hasErrors:=True).MakeCompilerGenerated()
                End If

                Throw ExceptionUtilities.UnexpectedValue(conversionSemantics)
            End If

            Dim delegateInvoke As MethodSymbol = targetDelegateType.DelegateInvokeMethod

            For Each delegateParam As ParameterSymbol In delegateInvoke.Parameters
                If delegateParam.IsByRef OrElse delegateParam.OriginalDefinition.Type.IsTypeParameter() Then
                    Dim restrictedType As TypeSymbol = Nothing
                    If delegateParam.Type.IsRestrictedTypeOrArrayType(restrictedType) Then
                        ReportDiagnostic(diagnostics, lambda.LambdaSymbol.Parameters(delegateParam.Ordinal).GetFirstLocation(),
                                         ERRID.ERR_RestrictedType1, restrictedType)
                    End If
                End If
            Next

            Dim delegateReturnType As TypeSymbol = delegateInvoke.ReturnType

            If delegateInvoke.OriginalDefinition.ReturnType.IsTypeParameter() Then
                Dim restrictedType As TypeSymbol = Nothing
                If delegateReturnType.IsRestrictedTypeOrArrayType(restrictedType) Then
                    Dim location As SyntaxNode

                    If lambda.Expression.Kind = BoundKind.RangeVariableAssignment Then
                        location = DirectCast(lambda.Expression, BoundRangeVariableAssignment).Value.Syntax
                    Else
                        location = lambda.Expression.Syntax
                    End If

                    ReportDiagnostic(diagnostics, location, ERRID.ERR_RestrictedType1, restrictedType)
                End If
            End If

            If lambda.LambdaSymbol.ReturnType Is LambdaSymbol.ReturnTypePendingDelegate Then
                lambda = lambda.Update(lambda.LambdaSymbol, lambda.RangeVariables,
                              ApplyImplicitConversion(lambda.Expression.Syntax, delegateReturnType, lambda.Expression,
                                                      diagnostics,
                                                      If(delegateReturnType.IsBooleanType(), lambda.ExprIsOperandOfConditionalBranch, False)),
                              exprIsOperandOfConditionalBranch:=False)
            Else
                lambda = lambda.Update(lambda.LambdaSymbol, lambda.RangeVariables,
                              lambda.Expression, exprIsOperandOfConditionalBranch:=False)
            End If

            If conversionSemantics = SyntaxKind.CTypeKeyword Then
                Return New BoundConversion(tree, lambda, convKind, False, isExplicit, targetType).MakeCompilerGenerated()
            ElseIf conversionSemantics = SyntaxKind.DirectCastKeyword Then
                Return New BoundDirectCast(tree, lambda, convKind, targetType).MakeCompilerGenerated()
            ElseIf conversionSemantics = SyntaxKind.TryCastKeyword Then
                Return New BoundTryCast(tree, lambda, convKind, targetType).MakeCompilerGenerated()
            End If

            Throw ExceptionUtilities.UnexpectedValue(conversionSemantics)
        End Function

        Private Function ReclassifyInterpolatedStringExpression(conversionSemantics As SyntaxKind, tree As SyntaxNode, convKind As ConversionKind, isExplicit As Boolean, node As BoundInterpolatedStringExpression, targetType As TypeSymbol, diagnostics As BindingDiagnosticBag) As BoundExpression

            If (convKind And ConversionKind.InterpolatedString) = ConversionKind.InterpolatedString Then
                Debug.Assert(targetType.Equals(Compilation.GetWellKnownType(WellKnownType.System_IFormattable)) OrElse targetType.Equals(Compilation.GetWellKnownType(WellKnownType.System_FormattableString)))
                Return New BoundConversion(tree,
                                           BindUnconvertedInterpolatedStringToFormattable(tree, node, targetType, diagnostics),
                                           ConversionKind.InterpolatedString, False, isExplicit, targetType)
            End If

            Return node

        End Function

        Private Function ReclassifyTupleLiteral(
                       convKind As ConversionKind,
                       tree As SyntaxNode,
                       isExplicit As Boolean,
                       sourceTuple As BoundTupleLiteral,
                       destination As TypeSymbol,
                       diagnostics As BindingDiagnosticBag) As BoundExpression

            ' We have a successful tuple conversion rather than producing a separate conversion node 
            ' which is a conversion on top of a tuple literal, tuple conversion is an element-wise conversion of arguments.
            Dim isNullableTupleConversion = (convKind And ConversionKind.Nullable) <> 0
            Debug.Assert(Not isNullableTupleConversion OrElse destination.IsNullableType())

            Dim targetType = destination

            If isNullableTupleConversion Then
                targetType = destination.GetNullableUnderlyingType()
            End If

            Dim arguments = sourceTuple.Arguments
            If Not targetType.IsTupleOrCompatibleWithTupleOfCardinality(arguments.Length) Then
                Return sourceTuple
            End If

            If targetType.IsTupleType Then
                Dim destTupleType = DirectCast(targetType, TupleTypeSymbol)

                TupleTypeSymbol.ReportNamesMismatchesIfAny(targetType, sourceTuple, diagnostics)

                ' do not lose the original element names in the literal if different from names in the target
                ' Come back to this, what about locations? (https:'github.com/dotnet/roslyn/issues/11013)
                targetType = destTupleType.WithElementNames(sourceTuple.ArgumentNamesOpt)
            End If

            Dim convertedArguments = ArrayBuilder(Of BoundExpression).GetInstance(arguments.Length)
            Dim targetElementTypes As ImmutableArray(Of TypeSymbol) = targetType.GetElementTypesOfTupleOrCompatible()
            Debug.Assert(targetElementTypes.Length = arguments.Length, "converting a tuple literal to incompatible type?")

            For i As Integer = 0 To arguments.Length - 1
                Dim argument = arguments(i)
                Dim destType = targetElementTypes(i)

                convertedArguments.Add(ApplyConversion(argument.Syntax, destType, argument, isExplicit, diagnostics))
            Next

            Dim result As BoundExpression = New BoundConvertedTupleLiteral(
                sourceTuple.Syntax,
                sourceTuple.Type,
                convertedArguments.ToImmutableAndFree(),
                targetType)

            If Not TypeSymbol.Equals(sourceTuple.Type, destination, TypeCompareKind.ConsiderEverything) AndAlso convKind <> Nothing Then
                ' literal cast is applied to the literal 
                result = New BoundConversion(sourceTuple.Syntax, result, convKind, checked:=False, explicitCastInCode:=isExplicit, type:=destination)
            End If

            ' If we had a cast in the code, keep conversion in the tree.
            ' even though the literal is already converted to the target type.
            If isExplicit Then
                result = New BoundConversion(
                    tree,
                    result,
                    ConversionKind.Identity,
                    checked:=False,
                    explicitCastInCode:=isExplicit,
                    type:=destination)
            End If

            Return result
        End Function

        Private Sub WarnOnNarrowingConversionBetweenSealedClassAndAnInterface(
            convKind As ConversionKind,
            location As SyntaxNode,
            sourceType As TypeSymbol,
            targetType As TypeSymbol,
            diagnostics As BindingDiagnosticBag
        )
            If Conversions.IsNarrowingConversion(convKind) Then
                Dim interfaceType As TypeSymbol = Nothing
                Dim classType As NamedTypeSymbol = Nothing

                If sourceType.IsInterfaceType() Then
                    If targetType.IsClassType() Then
                        interfaceType = sourceType
                        classType = DirectCast(targetType, NamedTypeSymbol)
                    End If
                ElseIf sourceType.IsClassType() AndAlso targetType.IsInterfaceType() Then
                    interfaceType = targetType
                    classType = DirectCast(sourceType, NamedTypeSymbol)
                End If

                Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics)

                If classType IsNot Nothing AndAlso
                    interfaceType IsNot Nothing AndAlso
                    classType.IsNotInheritable AndAlso
                    Not classType.IsComImport() AndAlso
                    Not Conversions.IsWideningConversion(Conversions.ClassifyDirectCastConversion(classType, interfaceType, useSiteInfo)) Then
                    ' Report specific warning if converting IEnumerable(Of XElement) to String.
                    If (targetType.SpecialType = SpecialType.System_String) AndAlso IsIEnumerableOfXElement(sourceType, useSiteInfo) Then
                        ReportDiagnostic(diagnostics, location, ERRID.WRN_UseValueForXmlExpression3, sourceType, targetType, sourceType)
                    Else
                        ReportDiagnostic(diagnostics, location, ERRID.WRN_InterfaceConversion2, sourceType, targetType)
                    End If
                End If

                diagnostics.AddDependencies(useSiteInfo)
            End If
        End Sub

        Private Shared Sub WarnOnLockConversion(sourceType As TypeSymbol, syntax As SyntaxNode, diagnostics As BindingDiagnosticBag)
            If sourceType IsNot Nothing AndAlso sourceType.IsWellKnownTypeLock() Then
                ReportDiagnostic(diagnostics, syntax, ERRID.WRN_ConvertingLock)
            End If
        End Sub

        Private Function IsIEnumerableOfXElement(type As TypeSymbol, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)) As Boolean
            Return type.IsOrImplementsIEnumerableOfXElement(Compilation, useSiteInfo)
        End Function

        Private Sub ReportNoConversionError(
            location As SyntaxNode,
            sourceType As TypeSymbol,
            targetType As TypeSymbol,
            diagnostics As BindingDiagnosticBag,
            Optional copybackConversionParamName As String = Nothing
        )
            If sourceType.IsArrayType() AndAlso targetType.IsArrayType() Then

                Dim sourceArray = DirectCast(sourceType, ArrayTypeSymbol)
                Dim targetArray = DirectCast(targetType, ArrayTypeSymbol)
                Dim sourceElement = sourceArray.ElementType
                Dim targetElement = targetArray.ElementType

                If sourceArray.Rank <> targetArray.Rank Then
                    ReportDiagnostic(diagnostics, location, ERRID.ERR_ConvertArrayRankMismatch2, sourceType, targetType)

                ElseIf sourceArray.IsSZArray <> targetArray.IsSZArray Then
                    ReportDiagnostic(diagnostics, location, ERRID.ERR_TypeMismatch2, sourceType, targetType)

                ElseIf Not (sourceElement.IsErrorType() OrElse targetElement.IsErrorType()) Then
                    Dim elemConv = Conversions.ClassifyDirectCastConversion(sourceElement, targetElement, CompoundUseSiteInfo(Of AssemblySymbol).Discarded)

                    If Not Conversions.IsIdentityConversion(elemConv) AndAlso
                       (targetElement.IsObjectType() OrElse targetElement.SpecialType = SpecialType.System_ValueType) AndAlso
                       Not sourceElement.IsReferenceType() Then

                        ReportDiagnostic(diagnostics, location, ERRID.ERR_ConvertObjectArrayMismatch3, sourceType, targetType, sourceElement)

                    ElseIf Not Conversions.IsIdentityConversion(elemConv) AndAlso
                        Not (Conversions.IsWideningConversion(elemConv) AndAlso
                             (elemConv And (ConversionKind.Reference Or ConversionKind.Value Or ConversionKind.TypeParameter)) <> 0) Then
                        ReportDiagnostic(diagnostics, location, ERRID.ERR_ConvertArrayMismatch4, sourceType, targetType, sourceElement, targetElement)

                    Else
                        ReportDiagnostic(diagnostics, location, ERRID.ERR_TypeMismatch2, sourceType, targetType)
                    End If
                End If

            ElseIf sourceType.IsDateTimeType() AndAlso targetType.IsDoubleType() Then
                ReportDiagnostic(diagnostics, location, ERRID.ERR_DateToDoubleConversion)

            ElseIf targetType.IsDateTimeType() AndAlso sourceType.IsDoubleType() Then
                ReportDiagnostic(diagnostics, location, ERRID.ERR_DoubleToDateConversion)

            ElseIf targetType.IsCharType() AndAlso sourceType.IsIntegralType() Then
                ReportDiagnostic(diagnostics, location, ERRID.ERR_IntegralToCharTypeMismatch1, sourceType)

            ElseIf sourceType.IsCharType() AndAlso targetType.IsIntegralType() Then
                ReportDiagnostic(diagnostics, location, ERRID.ERR_CharToIntegralTypeMismatch1, targetType)

            ElseIf copybackConversionParamName IsNot Nothing Then
                ReportDiagnostic(diagnostics, location, ERRID.ERR_CopyBackTypeMismatch3,
                                 copybackConversionParamName, sourceType, targetType)

            ElseIf sourceType.IsInterfaceType() AndAlso targetType.IsValueType() AndAlso IsIEnumerableOfXElement(sourceType, CompoundUseSiteInfo(Of AssemblySymbol).Discarded) Then
                ReportDiagnostic(diagnostics, location, ERRID.ERR_TypeMismatchForXml3, sourceType, targetType, sourceType)

            Else
                ReportDiagnostic(diagnostics, location, ERRID.ERR_TypeMismatch2, sourceType, targetType)
            End If
        End Sub

    End Class

End Namespace