File: Binding\Binder_Conversions.vb
Web Access
Project: src\src\Compilers\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj (Microsoft.CodeAnalysis.VisualBasic)
' Licensed to the .NET Foundation under one or more agreements.
' The .NET Foundation licenses this file to you under the MIT license.
' See the LICENSE file in the project root for more information.
 
Imports System.Collections.Immutable
Imports System.Runtime.InteropServices
Imports Microsoft.CodeAnalysis.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).Locations(0),
                                         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