/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Binding/Binder_Conversions.vb
1 816 строк
102 KB
Cyrus Najmabadi
Update code to use GetFirstLocation() instead of Locations[0] or Locations.First() (#80709)
21 окт 2025, 00:00
Не верифицирован
21 окт 2025, 00:00
3a723bb
Код
Авторство
О чём код?
' Licensed to the .NET Foundation under one or more agreements. ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. Imports System.Collections.Immutable Imports System.Runtime.InteropServices Imports Microsoft.CodeAnalysis.Collections Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports TypeKind = Microsoft.CodeAnalysis.TypeKind Namespace Microsoft.CodeAnalysis.VisualBasic ' Binding of conversion operators is implemented in this part. Partial Friend Class Binder Private Function BindCastExpression( node As CastExpressionSyntax, diagnostics As BindingDiagnosticBag ) As BoundExpression Dim result As BoundExpression Select Case node.Keyword.Kind Case SyntaxKind.CTypeKeyword result = BindCTypeExpression(node, diagnostics) Case SyntaxKind.DirectCastKeyword result = BindDirectCastExpression(node, diagnostics) Case SyntaxKind.TryCastKeyword result = BindTryCastExpression(node, diagnostics) Case Else Throw ExceptionUtilities.UnexpectedValue(node.Keyword.Kind) End Select Return result End Function Private Function BindCTypeExpression( node As CastExpressionSyntax, diagnostics As BindingDiagnosticBag ) As BoundExpression Debug.Assert(node.Keyword.Kind = SyntaxKind.CTypeKeyword) Dim argument = BindValue(node.Expression, diagnostics) Dim targetType = BindTypeSyntax(node.Type, diagnostics) Return ApplyConversion(node, targetType, argument, isExplicit:=True, diagnostics) End Function Private Function BindDirectCastExpression( node As CastExpressionSyntax, diagnostics As BindingDiagnosticBag ) As BoundExpression Debug.Assert(node.Keyword.Kind = SyntaxKind.DirectCastKeyword) Dim argument = BindValue(node.Expression, diagnostics) Dim targetType = BindTypeSyntax(node.Type, diagnostics) Return ApplyDirectCastConversion(node, argument, targetType, diagnostics) End Function Private Function ApplyDirectCastConversion( node As SyntaxNode, argument As BoundExpression, targetType As TypeSymbol, diagnostics As BindingDiagnosticBag ) As BoundExpression Debug.Assert(argument.IsValue) ' Deal with erroneous arguments If (argument.HasErrors OrElse targetType.IsErrorType) Then argument = MakeRValue(argument, diagnostics) Return New BoundDirectCast(node, argument, conversionKind:=Nothing, type:=targetType, hasErrors:=True) End If ' Classify conversion Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics) Dim conv As ConversionKind = Conversions.ClassifyDirectCastConversion(argument, targetType, Me, useSiteInfo) If diagnostics.Add(node, useSiteInfo) Then ' Suppress any additional diagnostics diagnostics = BindingDiagnosticBag.Discarded End If If ReclassifyExpression(argument, SyntaxKind.DirectCastKeyword, node, conv, True, targetType, diagnostics) Then If argument.Syntax IsNot node Then ' If its an explicit conversion, we must have a bound node that corresponds to that syntax node for GetSemanticInfo. ' Insert an identity conversion if necessary. Debug.Assert(argument.Kind <> BoundKind.DirectCast, "Associated wrong node with conversion?") argument = New BoundDirectCast(node, argument, ConversionKind.Identity, targetType) End If Return argument Else argument = MakeRValue(argument, diagnostics) End If If argument.HasErrors Then Return New BoundDirectCast(node, argument, conv, targetType, hasErrors:=True) End If Dim sourceType = argument.Type If sourceType IsNot Nothing AndAlso sourceType.IsErrorType() Then Return New BoundDirectCast(node, argument, conv, targetType, hasErrors:=True) End If Debug.Assert(argument.IsNothingLiteral() OrElse (sourceType IsNot Nothing AndAlso Not sourceType.IsErrorType())) ' Check for special error conditions If Conversions.NoConversion(conv) Then If sourceType.IsValueType AndAlso sourceType.IsRestrictedType() AndAlso (targetType.IsObjectType() OrElse targetType.SpecialType = SpecialType.System_ValueType) Then ReportDiagnostic(diagnostics, argument.Syntax, ERRID.ERR_RestrictedConversion1, sourceType) Return New BoundDirectCast(node, argument, conv, targetType, hasErrors:=True) End If End If WarnOnNarrowingConversionBetweenSealedClassAndAnInterface(conv, argument.Syntax, sourceType, targetType, diagnostics) If Conversions.NoConversion(conv) Then ReportNoConversionError(argument.Syntax, sourceType, targetType, diagnostics) Return New BoundDirectCast(node, argument, conv, targetType, hasErrors:=True) End If If Conversions.IsIdentityConversion(conv) Then If targetType.IsFloatingType() Then ReportDiagnostic(diagnostics, argument.Syntax, ERRID.ERR_IdentityDirectCastForFloat) ElseIf targetType.IsValueType Then ReportDiagnostic(diagnostics, argument.Syntax, ERRID.WRN_ObsoleteIdentityDirectCastForValueType) End If End If Dim integerOverflow As Boolean = False Dim constantResult = Conversions.TryFoldConstantConversion( argument, targetType, integerOverflow) If constantResult IsNot Nothing Then Debug.Assert(Conversions.IsIdentityConversion(conv) OrElse conv = ConversionKind.WideningNothingLiteral OrElse sourceType.GetEnumUnderlyingTypeOrSelf().IsSameTypeIgnoringAll(targetType.GetEnumUnderlyingTypeOrSelf())) Debug.Assert(Not integerOverflow) Debug.Assert(Not constantResult.IsBad) Else constantResult = Conversions.TryFoldNothingReferenceConversion(argument, conv, targetType) End If If Not Conversions.IsIdentityConversion(conv) Then WarnOnLockConversion(sourceType, argument.Syntax, diagnostics) End If Return New BoundDirectCast(node, argument, conv, constantResult, targetType) End Function Private Function BindTryCastExpression( node As CastExpressionSyntax, diagnostics As BindingDiagnosticBag ) As BoundExpression Debug.Assert(node.Keyword.Kind = SyntaxKind.TryCastKeyword) Dim argument = BindValue(node.Expression, diagnostics) Dim targetType = BindTypeSyntax(node.Type, diagnostics) Return ApplyTryCastConversion(node, argument, targetType, diagnostics) End Function Private Function ApplyTryCastConversion( node As SyntaxNode, argument As BoundExpression, targetType As TypeSymbol, diagnostics As BindingDiagnosticBag ) As BoundExpression Debug.Assert(argument.IsValue) ' Deal with erroneous arguments If (argument.HasErrors OrElse targetType.IsErrorType) Then argument = MakeRValue(argument, diagnostics) Return New BoundTryCast(node, argument, conversionKind:=Nothing, type:=targetType, hasErrors:=True) End If ' Classify conversion Dim conv As ConversionKind If targetType.IsReferenceType Then Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics) conv = Conversions.ClassifyTryCastConversion(argument, targetType, Me, useSiteInfo) If diagnostics.Add(node, useSiteInfo) Then ' Suppress any additional diagnostics diagnostics = BindingDiagnosticBag.Discarded End If Else conv = Nothing End If If ReclassifyExpression(argument, SyntaxKind.TryCastKeyword, node, conv, True, targetType, diagnostics) Then If argument.Syntax IsNot node Then ' If its an explicit conversion, we must have a bound node that corresponds to that syntax node for GetSemanticInfo. ' Insert an identity conversion if necessary. Debug.Assert(argument.Kind <> BoundKind.TryCast, "Associated wrong node with conversion?") argument = New BoundTryCast(node, argument, ConversionKind.Identity, targetType) End If Return argument Else argument = MakeRValue(argument, diagnostics) End If If argument.HasErrors Then Return New BoundTryCast(node, argument, conv, targetType, hasErrors:=True) End If Dim sourceType = argument.Type If sourceType IsNot Nothing AndAlso sourceType.IsErrorType() Then Return New BoundTryCast(node, argument, conv, targetType, hasErrors:=True) End If Debug.Assert(argument.IsNothingLiteral() OrElse (sourceType IsNot Nothing AndAlso Not sourceType.IsErrorType())) ' Check for special error conditions If Conversions.NoConversion(conv) Then If targetType.IsValueType() Then Dim castSyntax = TryCast(node, CastExpressionSyntax) ReportDiagnostic(diagnostics, If(castSyntax IsNot Nothing, castSyntax.Type, node), ERRID.ERR_TryCastOfValueType1, targetType) Return New BoundTryCast(node, argument, conv, targetType, hasErrors:=True) ElseIf targetType.IsTypeParameter() AndAlso Not targetType.IsReferenceType Then Dim castSyntax = TryCast(node, CastExpressionSyntax) ReportDiagnostic(diagnostics, If(castSyntax IsNot Nothing, castSyntax.Type, node), ERRID.ERR_TryCastOfUnconstrainedTypeParam1, targetType) Return New BoundTryCast(node, argument, conv, targetType, hasErrors:=True) ElseIf sourceType.IsValueType AndAlso sourceType.IsRestrictedType() AndAlso (targetType.IsObjectType() OrElse targetType.SpecialType = SpecialType.System_ValueType) Then ReportDiagnostic(diagnostics, argument.Syntax, ERRID.ERR_RestrictedConversion1, sourceType) Return New BoundTryCast(node, argument, conv, targetType, hasErrors:=True) End If End If WarnOnNarrowingConversionBetweenSealedClassAndAnInterface(conv, argument.Syntax, sourceType, targetType, diagnostics) If Conversions.NoConversion(conv) Then ReportNoConversionError(argument.Syntax, sourceType, targetType, diagnostics) Return New BoundTryCast(node, argument, conv, targetType, hasErrors:=True) End If Dim constantResult = Conversions.TryFoldNothingReferenceConversion(argument, conv, targetType) If Not Conversions.IsIdentityConversion(conv) Then WarnOnLockConversion(sourceType, argument.Syntax, diagnostics) End If Return New BoundTryCast(node, argument, conv, constantResult, targetType) End Function Private Function BindPredefinedCastExpression( node As PredefinedCastExpressionSyntax, diagnostics As BindingDiagnosticBag ) As BoundExpression Dim targetType As SpecialType Select Case node.Keyword.Kind Case SyntaxKind.CBoolKeyword : targetType = SpecialType.System_Boolean Case SyntaxKind.CByteKeyword : targetType = SpecialType.System_Byte Case SyntaxKind.CCharKeyword : targetType = SpecialType.System_Char Case SyntaxKind.CDateKeyword : targetType = SpecialType.System_DateTime Case SyntaxKind.CDecKeyword : targetType = SpecialType.System_Decimal Case SyntaxKind.CDblKeyword : targetType = SpecialType.System_Double Case SyntaxKind.CIntKeyword : targetType = SpecialType.System_Int32 Case SyntaxKind.CLngKeyword : targetType = SpecialType.System_Int64 Case SyntaxKind.CObjKeyword : targetType = SpecialType.System_Object Case SyntaxKind.CSByteKeyword : targetType = SpecialType.System_SByte Case SyntaxKind.CShortKeyword : targetType = SpecialType.System_Int16 Case SyntaxKind.CSngKeyword : targetType = SpecialType.System_Single Case SyntaxKind.CStrKeyword : targetType = SpecialType.System_String Case SyntaxKind.CUIntKeyword : targetType = SpecialType.System_UInt32 Case SyntaxKind.CULngKeyword : targetType = SpecialType.System_UInt64 Case SyntaxKind.CUShortKeyword : targetType = SpecialType.System_UInt16 Case Else Throw ExceptionUtilities.UnexpectedValue(node.Keyword.Kind) End Select Return ApplyConversion(node, GetSpecialType(targetType, node.Keyword, diagnostics), BindValue(node.Expression, diagnostics), isExplicit:=True, diagnostics:=diagnostics) End Function ''' <summary> ''' This function must return a BoundConversion node in case of non-identity conversion. ''' </summary> Friend Function ApplyImplicitConversion( node As SyntaxNode, targetType As TypeSymbol, expression As BoundExpression, diagnostics As BindingDiagnosticBag, Optional isOperandOfConditionalBranch As Boolean = False ) As BoundExpression Return ApplyConversion(node, targetType, expression, False, diagnostics, isOperandOfConditionalBranch:=isOperandOfConditionalBranch) End Function ''' <summary> ''' This function must return a BoundConversion node in case of explicit or non-identity conversion. ''' </summary> Private Function ApplyConversion( node As SyntaxNode, targetType As TypeSymbol, argument As BoundExpression, isExplicit As Boolean, diagnostics As BindingDiagnosticBag, Optional isOperandOfConditionalBranch As Boolean = False, Optional explicitSemanticForConcatArgument As Boolean = False ) As BoundExpression Debug.Assert(node IsNot Nothing) Debug.Assert(Not isOperandOfConditionalBranch OrElse Not isExplicit) Debug.Assert(argument.IsValue()) ' Deal with erroneous arguments If targetType.IsErrorType Then argument = MakeRValueAndIgnoreDiagnostics(argument) If Not isExplicit AndAlso argument.Type.IsSameTypeIgnoringAll(targetType) Then Return argument End If Return New BoundConversion(node, argument, conversionKind:=Nothing, checked:=CheckOverflow, explicitCastInCode:=isExplicit, type:=targetType, hasErrors:=True) End If If argument.HasErrors Then ' Suppress any additional diagnostics produced by this function diagnostics = BindingDiagnosticBag.Discarded End If ' Classify conversion Dim conv As KeyValuePair(Of ConversionKind, MethodSymbol) Dim applyNullableIsTrueOperator As Boolean = False Dim isTrueOperator As OverloadResolution.OverloadResolutionResult = Nothing Dim result As BoundExpression Debug.Assert(Not isOperandOfConditionalBranch OrElse targetType.IsBooleanType()) Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics) If isOperandOfConditionalBranch AndAlso targetType.IsBooleanType() Then Debug.Assert(Not isExplicit) conv = Conversions.ClassifyConversionOfOperandOfConditionalBranch(argument, targetType, Me, applyNullableIsTrueOperator, isTrueOperator, useSiteInfo) If diagnostics.Add(node, useSiteInfo) Then ' Suppress any additional diagnostics diagnostics = BindingDiagnosticBag.Discarded End If If isTrueOperator.BestResult.HasValue Then ' Apply IsTrue operator. Dim isTrue As BoundUserDefinedUnaryOperator = BindUserDefinedUnaryOperator(node, UnaryOperatorKind.IsTrue, argument, isTrueOperator, diagnostics) isTrue.SetWasCompilerGenerated() isTrue.UnderlyingExpression.SetWasCompilerGenerated() result = isTrue Else Dim intermediateTargetType As TypeSymbol If applyNullableIsTrueOperator Then ' Note, use site error will be reported by ApplyNullableIsTrueOperator later. Dim nullableOfT As NamedTypeSymbol = Compilation.GetSpecialType(SpecialType.System_Nullable_T) intermediateTargetType = Compilation.GetSpecialType(SpecialType.System_Nullable_T). Construct(ImmutableArray.Create(Of TypeSymbol)(targetType)) Else intermediateTargetType = targetType End If result = CreateConversionAndReportDiagnostic(node, argument, conv, isExplicit, intermediateTargetType, diagnostics) End If If applyNullableIsTrueOperator Then result = Binder.ApplyNullableIsTrueOperator(result, targetType) End If Else conv = Conversions.ClassifyConversion(argument, targetType, Me, useSiteInfo) If diagnostics.Add(node, useSiteInfo) Then ' Suppress any additional diagnostics diagnostics = BindingDiagnosticBag.Discarded End If result = CreateConversionAndReportDiagnostic(node, argument, conv, isExplicit, targetType, diagnostics, explicitSemanticForConcatArgument:=explicitSemanticForConcatArgument) End If Return result End Function Private Shared Function ApplyNullableIsTrueOperator(argument As BoundExpression, booleanType As TypeSymbol) As BoundNullableIsTrueOperator Debug.Assert(argument.Type.IsNullableOfBoolean() AndAlso booleanType.IsBooleanType()) Return New BoundNullableIsTrueOperator(argument.Syntax, argument, booleanType).MakeCompilerGenerated() End Function ''' <summary> ''' This function must return a BoundConversion node in case of non-identity conversion. ''' </summary> Private Function CreateConversionAndReportDiagnostic( tree As SyntaxNode, argument As BoundExpression, convKind As KeyValuePair(Of ConversionKind, MethodSymbol), isExplicit As Boolean, targetType As TypeSymbol, diagnostics As BindingDiagnosticBag, Optional copybackConversionParamName As String = Nothing, Optional explicitSemanticForConcatArgument As Boolean = False ) As BoundExpression Debug.Assert(argument.IsValue()) ' We need to preserve any conversion that was explicitly written in code ' (so that GetSemanticInfo can find the syntax in the bound tree). Implicit identity conversion ' don't need representation in the bound tree (they would be optimized away in emit, but are so common ' that this is an important way to save both time and memory). If (Not isExplicit OrElse explicitSemanticForConcatArgument) AndAlso Conversions.IsIdentityConversion(convKind.Key) Then Debug.Assert(argument.Type.IsSameTypeIgnoringAll(targetType)) Debug.Assert(tree Is argument.Syntax) Return MakeRValue(argument, diagnostics) End If If (convKind.Key And ConversionKind.UserDefined) = 0 AndAlso ReclassifyExpression(argument, SyntaxKind.CTypeKeyword, tree, convKind.Key, isExplicit, targetType, diagnostics) Then argument = MakeRValue(argument, diagnostics) If isExplicit AndAlso argument.Syntax IsNot tree Then ' If its an explicit conversion, we must have a bound node that corresponds to that syntax node for GetSemanticInfo. ' Insert an identity conversion if necessary. Debug.Assert(argument.Kind <> BoundKind.Conversion, "Associated wrong node with conversion?") argument = New BoundConversion(tree, argument, ConversionKind.Identity, CheckOverflow, isExplicit, targetType) End If Return argument ElseIf Not argument.IsNothingLiteral() AndAlso argument.Kind <> BoundKind.ArrayLiteral Then argument = MakeRValue(argument, diagnostics) End If Debug.Assert(argument.Kind <> BoundKind.Conversion OrElse DirectCast(argument, BoundConversion).ExplicitCastInCode OrElse Not argument.IsNothingLiteral() OrElse TypeOf argument.Syntax.Parent Is BinaryExpressionSyntax OrElse TypeOf argument.Syntax.Parent Is UnaryExpressionSyntax OrElse TypeOf argument.Syntax.Parent Is TupleExpressionSyntax OrElse (TypeOf argument.Syntax.Parent Is AssignmentStatementSyntax AndAlso argument.Syntax.Parent.Kind <> SyntaxKind.SimpleAssignmentStatement), "Applying yet another conversion to an implicit conversion from NOTHING, probably MakeRValue was called too early.") Dim sourceType = argument.Type ' At this point if the expression is an array literal then the conversion must be user defined. Debug.Assert(argument.Kind <> BoundKind.ArrayLiteral OrElse (convKind.Key And ConversionKind.UserDefined) <> 0) Dim reportArrayLiteralElementNarrowingConversion = False If argument.Kind = BoundKind.ArrayLiteral Then ' The array will get the type from the input type of the user defined conversion. sourceType = convKind.Value.Parameters(0).Type ' If the conversion from the inferred element type to the source type of the user defined conversion is a narrowing conversion then ' skip to the user defined conversion. Conversion errors on the individual elements will be reported when the array literal is reclassified. Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics) reportArrayLiteralElementNarrowingConversion = Not isExplicit AndAlso Conversions.IsNarrowingConversion(convKind.Key) AndAlso Conversions.IsNarrowingConversion(Conversions.ClassifyArrayLiteralConversion(DirectCast(argument, BoundArrayLiteral), sourceType, Me, useSiteInfo)) diagnostics.Add(argument.Syntax, useSiteInfo) If reportArrayLiteralElementNarrowingConversion Then GoTo DoneWithDiagnostics End If End If If argument.HasErrors Then GoTo DoneWithDiagnostics End If If sourceType IsNot Nothing AndAlso sourceType.IsErrorType() Then GoTo DoneWithDiagnostics End If Debug.Assert(argument.IsNothingLiteral() OrElse (sourceType IsNot Nothing AndAlso Not sourceType.IsErrorType())) ' Check for special error conditions If Conversions.NoConversion(convKind.Key) Then If sourceType.IsValueType AndAlso sourceType.IsRestrictedType() AndAlso (targetType.IsObjectType() OrElse targetType.SpecialType = SpecialType.System_ValueType) Then ReportDiagnostic(diagnostics, argument.Syntax, ERRID.ERR_RestrictedConversion1, sourceType) Return New BoundConversion(tree, argument, convKind.Key, CheckOverflow, isExplicit, targetType, hasErrors:=True) End If End If WarnOnNarrowingConversionBetweenSealedClassAndAnInterface(convKind.Key, argument.Syntax, sourceType, targetType, diagnostics) ' Deal with implicit narrowing conversions If Not isExplicit AndAlso Conversions.IsNarrowingConversion(convKind.Key) AndAlso (convKind.Key And ConversionKind.InvolvesNarrowingFromNumericConstant) = 0 Then If copybackConversionParamName IsNot Nothing Then If OptionStrict = VisualBasic.OptionStrict.On Then ReportDiagnostic(diagnostics, argument.Syntax, ERRID.ERR_StrictArgumentCopyBackNarrowing3, copybackConversionParamName, sourceType, targetType) ElseIf OptionStrict = VisualBasic.OptionStrict.Custom Then ReportDiagnostic(diagnostics, argument.Syntax, ERRID.WRN_ImplicitConversionCopyBack, copybackConversionParamName, sourceType, targetType) End If Else ' We have a narrowing conversion. This is how we might display it, depending on context: ' ERR_NarrowingConversionDisallowed2 "Option Strict On disallows implicit conversions from '|1' to '|2'." ' ERR_NarrowingConversionCollection2 "Option Strict On disallows implicit conversions from '|1' to '|2'; ' the Visual Basic 6.0 collection type is not compatible with the .NET Framework collection type." ' ERR_AmbiguousCastConversion2 "Option Strict On disallows implicit conversions from '|1' to '|2' because the conversion is ambiguous." ' The Collection error is for when one type is Microsoft.VisualBasic.Collection and ' the other type is named _Collection. ' The Ambiguous error is for when the conversion was classed as "Narrowing" for reasons of ambiguity. If OptionStrict = VisualBasic.OptionStrict.On Then If Not MakeVarianceConversionSuggestion(convKind.Key, argument.Syntax, sourceType, targetType, diagnostics, justWarn:=False) Then Dim err As ERRID = ERRID.ERR_NarrowingConversionDisallowed2 Const _Collection As String = "_Collection" If (convKind.Key And ConversionKind.VarianceConversionAmbiguity) <> 0 Then err = ERRID.ERR_AmbiguousCastConversion2 ElseIf (sourceType.IsMicrosoftVisualBasicCollection() AndAlso String.Equals(targetType.Name, _Collection, StringComparison.Ordinal)) OrElse (String.Equals(sourceType.Name, _Collection, StringComparison.Ordinal) AndAlso targetType.IsMicrosoftVisualBasicCollection()) Then ' Got both, so use the more specific error message err = ERRID.ERR_NarrowingConversionCollection2 End If ReportDiagnostic(diagnostics, argument.Syntax, err, sourceType, targetType) End If ElseIf OptionStrict = VisualBasic.OptionStrict.Custom Then ' Avoid reporting a warning if narrowing caused exclusively by "zero argument" relaxation ' for an Anonymous Delegate. Note, that dropping a return is widening. If (convKind.Key And ConversionKind.AnonymousDelegate) = 0 OrElse (convKind.Key And ConversionKind.DelegateRelaxationLevelMask) <> ConversionKind.DelegateRelaxationLevelWideningDropReturnOrArgs Then If Not MakeVarianceConversionSuggestion(convKind.Key, argument.Syntax, sourceType, targetType, diagnostics, justWarn:=True) Then Dim wrnId1 As ERRID = ERRID.WRN_ImplicitConversionSubst1 Dim wrnId2 As ERRID = ERRID.WRN_ImplicitConversion2 If (convKind.Key And ConversionKind.VarianceConversionAmbiguity) <> 0 Then wrnId2 = ERRID.WRN_AmbiguousCastConversion2 End If ReportDiagnostic(diagnostics, argument.Syntax, wrnId1, ErrorFactory.ErrorInfo(wrnId2, sourceType, targetType)) End If End If End If End If End If If Conversions.NoConversion(convKind.Key) Then If Conversions.FailedDueToNumericOverflow(convKind.Key) Then Dim errorTargetType As TypeSymbol If (convKind.Key And ConversionKind.UserDefined) <> 0 AndAlso convKind.Value IsNot Nothing Then errorTargetType = convKind.Value.Parameters(0).Type Else errorTargetType = targetType End If ReportDiagnostic(diagnostics, argument.Syntax, ERRID.ERR_ExpressionOverflow1, errorTargetType) ElseIf isExplicit OrElse Not MakeVarianceConversionSuggestion(convKind.Key, argument.Syntax, sourceType, targetType, diagnostics, justWarn:=False) Then ReportNoConversionError(argument.Syntax, sourceType, targetType, diagnostics, copybackConversionParamName) End If Return New BoundConversion(tree, argument, convKind.Key And (Not ConversionKind.UserDefined), CheckOverflow, isExplicit, targetType, hasErrors:=True) End If DoneWithDiagnostics: If (convKind.Key And ConversionKind.UserDefined) <> 0 Then Return CreateUserDefinedConversion(tree, argument, convKind, isExplicit, targetType, reportArrayLiteralElementNarrowingConversion, diagnostics) End If If argument.HasErrors OrElse (sourceType IsNot Nothing AndAlso sourceType.IsErrorType()) Then Return New BoundConversion(tree, argument, convKind.Key, CheckOverflow, isExplicit, targetType, hasErrors:=True) End If Return CreatePredefinedConversion(tree, argument, convKind.Key, isExplicit, targetType, diagnostics) End Function Private Structure VarianceSuggestionTypeParameterInfo Private _isViable As Boolean Private _typeParameter As TypeParameterSymbol Private _derivedArgument As TypeSymbol Private _baseArgument As TypeSymbol Public Sub [Set](parameter As TypeParameterSymbol, derived As TypeSymbol, base As TypeSymbol) _typeParameter = parameter _derivedArgument = derived _baseArgument = base _isViable = True End Sub Public ReadOnly Property IsViable As Boolean Get Return _isViable End Get End Property Public ReadOnly Property TypeParameter As TypeParameterSymbol Get Return _typeParameter End Get End Property Public ReadOnly Property DerivedArgument As TypeSymbol Get Return _derivedArgument End Get End Property Public ReadOnly Property BaseArgument As TypeSymbol Get Return _baseArgument End Get End Property End Structure ''' <summary> ''' Returns True if error or warning was reported. ''' ''' This function is invoked on the occasion of a Narrowing or NoConversion. ''' It looks at the conversion. If the conversion could have been helped by variance in ''' some way, it reports an error/warning message to that effect and returns true. This ''' message is a substitute for whatever other conversion-failed message might have been displayed. ''' ''' Note: these variance-related messages will NOT show auto-correct suggestion of using CType. That's ''' because, in these cases, it's more likely than not that CType will fail, so it would be a bad suggestion ''' </summary> Private Function MakeVarianceConversionSuggestion( convKind As ConversionKind, location As SyntaxNode, sourceType As TypeSymbol, targetType As TypeSymbol, diagnostics As BindingDiagnosticBag, justWarn As Boolean ) As Boolean Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics) Dim result As Boolean = MakeVarianceConversionSuggestion(convKind, location, sourceType, targetType, diagnostics, useSiteInfo, justWarn) diagnostics.AddDependencies(useSiteInfo) Return result End Function Private Function MakeVarianceConversionSuggestion( convKind As ConversionKind, location As SyntaxNode, sourceType As TypeSymbol, targetType As TypeSymbol, diagnostics As BindingDiagnosticBag, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol), justWarn As Boolean ) As Boolean If (convKind And ConversionKind.UserDefined) <> 0 Then Return False End If ' Variance scenario 2: Dim x As List(Of Animal) = New List(Of Tiger) ' "List(Of Tiger) cannot be converted to List(Of Animal). Consider using IEnumerable(Of Animal) instead." ' ' (1) If the user attempts a conversion to DEST which is a generic binding of one of the non-variant ' standard generic collection types List(Of D), Collection(Of D), ReadOnlyCollection(Of D), ' IList(Of D), ICollection(Of D) ' (2) and if the conversion failed (either ConversionNarrowing or ConversionError), ' (3) and if the source type SOURCE implemented/inherited exactly one binding ISOURCE=G(Of S) of that ' generic collection type G ' (4) and if there is a reference conversion from S to D ' (5) Then report "G(Of S) cannot be converted to G(Of D). Consider converting to IEnumerable(Of D) instead." If targetType.Kind <> SymbolKind.NamedType Then Return False End If Dim targetNamedType = DirectCast(targetType, NamedTypeSymbol) If Not targetNamedType.IsGenericType Then Return False End If Dim targetGenericDefinition As NamedTypeSymbol = targetNamedType.OriginalDefinition If targetGenericDefinition.SpecialType = SpecialType.System_Collections_Generic_IList_T OrElse targetGenericDefinition.SpecialType = SpecialType.System_Collections_Generic_ICollection_T OrElse targetGenericDefinition.SpecialType = SpecialType.System_Collections_Generic_IReadOnlyList_T OrElse targetGenericDefinition.SpecialType = SpecialType.System_Collections_Generic_IReadOnlyCollection_T OrElse targetGenericDefinition Is Compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_List_T) OrElse targetGenericDefinition Is Compilation.GetWellKnownType(WellKnownType.System_Collections_ObjectModel_Collection_T) OrElse targetGenericDefinition Is Compilation.GetWellKnownType(WellKnownType.System_Collections_ObjectModel_ReadOnlyCollection_T) Then Dim sourceTypeArgument As TypeSymbol = Nothing If targetGenericDefinition.IsInterfaceType() Then Dim matchingInterfaces As New HashSet(Of NamedTypeSymbol)() If IsOrInheritsFromOrImplementsInterface(sourceType, targetGenericDefinition, useSiteInfo:=useSiteInfo, matchingInterfaces:=matchingInterfaces) AndAlso matchingInterfaces.Count = 1 Then sourceTypeArgument = matchingInterfaces(0).TypeArgumentsNoUseSiteDiagnostics(0) End If Else Dim typeToCheck As TypeSymbol = sourceType Do If typeToCheck.OriginalDefinition Is targetGenericDefinition Then sourceTypeArgument = DirectCast(typeToCheck, NamedTypeSymbol).TypeArgumentsNoUseSiteDiagnostics(0) Exit Do End If typeToCheck = typeToCheck.BaseTypeNoUseSiteDiagnostics Loop While typeToCheck IsNot Nothing End If If sourceTypeArgument IsNot Nothing AndAlso Conversions.IsWideningConversion(Conversions.Classify_Reference_Array_TypeParameterConversion(sourceTypeArgument, targetNamedType.TypeArgumentsNoUseSiteDiagnostics(0), varianceCompatibilityClassificationDepth:=0, useSiteInfo:=useSiteInfo)) Then Dim iEnumerable_T As NamedTypeSymbol = Compilation.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T) If Not iEnumerable_T.IsErrorType() Then Dim suggestion As NamedTypeSymbol = iEnumerable_T.Construct(targetNamedType.TypeArgumentsNoUseSiteDiagnostics(0)) If justWarn Then ReportDiagnostic(diagnostics, location, ERRID.WRN_ImplicitConversionSubst1, ErrorFactory.ErrorInfo(ERRID.WRN_VarianceIEnumerableSuggestion3, sourceType, targetType, suggestion)) Else ReportDiagnostic(diagnostics, location, ERRID.ERR_VarianceIEnumerableSuggestion3, sourceType, targetType, suggestion) End If Return True End If End If End If ' Variance scenario 1: | Variance scenario 3: ' Dim x as IEnumerable(Of Tiger) = New List(Of Animal) | Dim x As IGoo(Of Animal) = New MyGoo ' "List(Of Animal) cannot be converted to | "MyGoo cannot be converted to IGoo(Of Animal). ' IEnumerable(Of Tiger) because 'Animal' is not derived | Consider changing the 'T' in the definition ' from 'Tiger', as required for the 'Out' generic | of interface IGoo(Of T) to an Out type ' parameter 'T' in 'IEnumerable(Of Out T)'" | parameter, Out T." ' | ' (1) If the user attempts a conversion to | (1) If the user attempts a conversion to some ' some target type DEST=G(Of D1,D2,...) which is | target type DEST=G(Of D1,D2,...) which is ' a generic instantiation of some variant interface/| a generic instantiation of some interface/delegate ' delegate type G(Of T1,T2,...), | type G(...), which NEED NOT be variant! ' (2) and if the conversion fails (Narrowing/Error), | (2) and if the type G is defined in source-code, ' (3) and if the source type SOURCE implements/ | not imported metadata. And the conversion fails. ' inherits exactly one binding INHSOURCE= | (3) And INHSOURCE=exactly one binding of G ' G(Of S1,S2,...) of that generic type G, | (4) And if ever difference is either Di/Si/Ti ' (4) and if the only differences between (D1,D2,...) | where Ti has In/Out variance, or is ' and (S1,S2,...) occur in positions "Di/Si" | Dj/Sj/Tj such that Tj has no variance and ' such that the corresponding Ti has either In | Dj has a CLR conversion to Sj or vice versa ' or Out variance | (5) Then pick the first difference Dj/Sj ' (5) Then pick on the one such difference Si/Di/Ti | (6) and report "SOURCE cannot be converted to ' (6) and report "SOURCE cannot be converted to DEST | DEST. Consider changing Tj in the definition ' because Si is not derived from Di, as required | of interface/delegate IGoo(Of T) to an ' for the 'In/Out' generic parameter 'T' in | In/Out type parameter, In/Out T". ' 'IEnumerable(Of Out T)'" | Dim matchingGenericInstantiation As NamedTypeSymbol ' (1) If the user attempts a conversion Select Case targetGenericDefinition.TypeKind Case TypeKind.Delegate If sourceType.OriginalDefinition Is targetGenericDefinition Then matchingGenericInstantiation = DirectCast(sourceType, NamedTypeSymbol) Else Return False End If Case TypeKind.Interface Dim matchingInterfaces As New HashSet(Of NamedTypeSymbol)() If IsOrInheritsFromOrImplementsInterface(sourceType, targetGenericDefinition, useSiteInfo:=useSiteInfo, matchingInterfaces:=matchingInterfaces) AndAlso matchingInterfaces.Count = 1 Then matchingGenericInstantiation = matchingInterfaces(0) Else Return False End If Case Else Return False End Select ' (3) and if the source type implemented exactly one binding of it... Dim source As NamedTypeSymbol = matchingGenericInstantiation Dim destination As NamedTypeSymbol = targetNamedType Dim oneVariantDifference As VarianceSuggestionTypeParameterInfo = Nothing ' for Di/Si/Ti Dim oneInvariantConvertibleDifference As TypeParameterSymbol = Nothing 'for Dj/Sj/Tj where Sj<Dj Dim oneInvariantReverseConvertibleDifference As TypeParameterSymbol = Nothing ' Dj/Sj/Tj where Dj<Sj Do Dim typeParameters As ImmutableArray(Of TypeParameterSymbol) = source.TypeParameters Dim sourceArguments As ImmutableArray(Of TypeSymbol) = source.TypeArgumentsNoUseSiteDiagnostics Dim destinationArguments As ImmutableArray(Of TypeSymbol) = destination.TypeArgumentsNoUseSiteDiagnostics For i As Integer = 0 To typeParameters.Length - 1 Dim sourceArg As TypeSymbol = sourceArguments(i) Dim destinationArg As TypeSymbol = destinationArguments(i) If sourceArg.IsSameTypeIgnoringAll(destinationArg) Then Continue For End If If sourceArg.IsErrorType() OrElse destinationArg.IsErrorType() Then Continue For End If Dim conv As ConversionKind = Nothing Select Case typeParameters(i).Variance Case VarianceKind.Out If sourceArg.IsValueType OrElse destinationArg.IsValueType Then oneVariantDifference.Set(typeParameters(i), sourceArg, destinationArg) Else conv = Conversions.Classify_Reference_Array_TypeParameterConversion(sourceArg, destinationArg, varianceCompatibilityClassificationDepth:=0, useSiteInfo:=useSiteInfo) If Not Conversions.IsWideningConversion(conv) Then If Not Conversions.IsNarrowingConversion(conv) OrElse (conv And ConversionKind.VarianceConversionAmbiguity) = 0 Then oneVariantDifference.Set(typeParameters(i), sourceArg, destinationArg) End If End If End If Case VarianceKind.In If sourceArg.IsValueType OrElse destinationArg.IsValueType Then oneVariantDifference.Set(typeParameters(i), destinationArg, sourceArg) Else conv = Conversions.Classify_Reference_Array_TypeParameterConversion(destinationArg, sourceArg, varianceCompatibilityClassificationDepth:=0, useSiteInfo:=useSiteInfo) If Not Conversions.IsWideningConversion(conv) Then If (targetNamedType.IsDelegateType AndAlso destinationArg.IsReferenceType AndAlso sourceArg.IsReferenceType) OrElse Not Conversions.IsNarrowingConversion(conv) OrElse (conv And ConversionKind.VarianceConversionAmbiguity) = 0 Then oneVariantDifference.Set(typeParameters(i), destinationArg, sourceArg) End If End If End If Case Else conv = Conversions.ClassifyDirectCastConversion(sourceArg, destinationArg, useSiteInfo) If Conversions.IsWideningConversion(conv) Then oneInvariantConvertibleDifference = typeParameters(i) Else conv = Conversions.ClassifyDirectCastConversion(destinationArg, sourceArg, useSiteInfo) If Conversions.IsWideningConversion(conv) Then oneInvariantReverseConvertibleDifference = typeParameters(i) Else Return False End If End If End Select Next source = source.ContainingType destination = destination.ContainingType Loop While source IsNot Nothing ' (5) If a Di/Si/Ti, and no Dj/Sj/Tj nor Dk/Sk/Tk, then report... If oneVariantDifference.IsViable AndAlso oneInvariantConvertibleDifference Is Nothing AndAlso oneInvariantReverseConvertibleDifference Is Nothing Then Dim containerFormatter As FormattedSymbol If oneVariantDifference.TypeParameter.ContainingType.IsDelegateType Then containerFormatter = CustomSymbolDisplayFormatter.DelegateSignature(oneVariantDifference.TypeParameter.ContainingSymbol) Else containerFormatter = CustomSymbolDisplayFormatter.ErrorNameWithKind(oneVariantDifference.TypeParameter.ContainingSymbol) End If If justWarn Then ReportDiagnostic(diagnostics, location, ERRID.WRN_ImplicitConversionSubst1, ErrorFactory.ErrorInfo(If(oneVariantDifference.TypeParameter.Variance = VarianceKind.Out, ERRID.WRN_VarianceConversionFailedOut6, ERRID.WRN_VarianceConversionFailedIn6), oneVariantDifference.DerivedArgument, oneVariantDifference.BaseArgument, oneVariantDifference.TypeParameter.Name, containerFormatter, sourceType, targetType)) Else ReportDiagnostic(diagnostics, location, If(oneVariantDifference.TypeParameter.Variance = VarianceKind.Out, ERRID.ERR_VarianceConversionFailedOut6, ERRID.ERR_VarianceConversionFailedIn6), oneVariantDifference.DerivedArgument, oneVariantDifference.BaseArgument, oneVariantDifference.TypeParameter.Name, containerFormatter, sourceType, targetType) End If Return True End If ' (5b) Otherwise, if a Dj/Sj/Tj and no Dk/Sk/Tk, and G came not from metadata, then report... If (oneInvariantConvertibleDifference IsNot Nothing OrElse oneInvariantReverseConvertibleDifference IsNot Nothing) AndAlso targetType.ContainingModule Is Compilation.SourceModule Then Dim oneInvariantDifference As TypeParameterSymbol If oneInvariantConvertibleDifference IsNot Nothing Then oneInvariantDifference = oneInvariantConvertibleDifference Else oneInvariantDifference = oneInvariantReverseConvertibleDifference End If Dim containerFormatter As FormattedSymbol If oneInvariantDifference.ContainingType.IsDelegateType Then containerFormatter = CustomSymbolDisplayFormatter.DelegateSignature(oneInvariantDifference.ContainingSymbol) Else containerFormatter = CustomSymbolDisplayFormatter.ErrorNameWithKind(oneInvariantDifference.ContainingSymbol) End If If justWarn Then ReportDiagnostic(diagnostics, location, ERRID.WRN_ImplicitConversionSubst1, ErrorFactory.ErrorInfo(If(oneInvariantConvertibleDifference IsNot Nothing, ERRID.WRN_VarianceConversionFailedTryOut4, ERRID.WRN_VarianceConversionFailedTryIn4), sourceType, targetType, oneInvariantDifference.Name, containerFormatter)) Else ReportDiagnostic(diagnostics, location, If(oneInvariantConvertibleDifference IsNot Nothing, ERRID.ERR_VarianceConversionFailedTryOut4, ERRID.ERR_VarianceConversionFailedTryIn4), sourceType, targetType, oneInvariantDifference.Name, containerFormatter) End If Return True End If Return False End Function Private Function CreatePredefinedConversion( tree As SyntaxNode, argument As BoundExpression, convKind As ConversionKind, isExplicit As Boolean, targetType As TypeSymbol, diagnostics As BindingDiagnosticBag ) As BoundConversion Debug.Assert(Conversions.ConversionExists(convKind) AndAlso (convKind And ConversionKind.UserDefined) = 0) Dim sourceType = argument.Type ' Handle Anonymous Delegate conversion. If (convKind And ConversionKind.AnonymousDelegate) <> 0 Then ' Don't spend time building a narrowing relaxation stub if we already complained about the narrowing. If isExplicit OrElse OptionStrict <> VisualBasic.OptionStrict.On OrElse Conversions.IsWideningConversion(convKind) Then Debug.Assert(Not Conversions.IsIdentityConversion(convKind)) Debug.Assert(sourceType.IsDelegateType() AndAlso DirectCast(sourceType, NamedTypeSymbol).IsAnonymousType AndAlso targetType.IsDelegateType() AndAlso targetType.SpecialType <> SpecialType.System_MulticastDelegate) Dim boundLambdaOpt As BoundLambda = Nothing Dim relaxationReceiverPlaceholderOpt As BoundRValuePlaceholder = Nothing Dim methodToConvert As MethodSymbol = DirectCast(sourceType, NamedTypeSymbol).DelegateInvokeMethod If (convKind And ConversionKind.NeedAStub) <> 0 Then Dim relaxationBinder As Binder ' If conversion is explicit, use Option Strict Off. If isExplicit AndAlso Me.OptionStrict <> VisualBasic.OptionStrict.Off Then relaxationBinder = New OptionStrictOffBinder(Me) Else relaxationBinder = Me End If Debug.Assert(Not isExplicit OrElse relaxationBinder.OptionStrict = VisualBasic.OptionStrict.Off) boundLambdaOpt = relaxationBinder.BuildDelegateRelaxationLambda(tree, tree, argument, methodToConvert, Nothing, QualificationKind.QualifiedViaValue, DirectCast(targetType, NamedTypeSymbol).DelegateInvokeMethod, convKind And ConversionKind.DelegateRelaxationLevelMask, isZeroArgumentKnownToBeUsed:=False, warnIfResultOfAsyncMethodIsDroppedDueToRelaxation:=False, diagnostics:=diagnostics, relaxationReceiverPlaceholder:=relaxationReceiverPlaceholderOpt) End If ' The conversion has the lambda stored internally to not clutter the bound tree with synthesized nodes ' in the first pass. Later the node get's rewritten into a delegate creation with the lambda if needed. Return New BoundConversion(tree, argument, convKind, False, isExplicit, Nothing, If(boundLambdaOpt Is Nothing, Nothing, New BoundRelaxationLambda(tree, boundLambdaOpt, relaxationReceiverPlaceholderOpt).MakeCompilerGenerated()), targetType) Else Debug.Assert(Not diagnostics.AccumulatesDiagnostics OrElse diagnostics.HasAnyErrors()) End If End If Dim integerOverflow As Boolean = False Dim constantResult = Conversions.TryFoldConstantConversion( argument, targetType, integerOverflow) If constantResult IsNot Nothing Then ' Overflow should have been detected at classification time. Debug.Assert(Not integerOverflow OrElse Not CheckOverflow) Debug.Assert(Not constantResult.IsBad) Else constantResult = Conversions.TryFoldNothingReferenceConversion(argument, convKind, targetType) End If Dim tupleElements As BoundConvertedTupleElements = CreateConversionForTupleElements(tree, sourceType, targetType, convKind, isExplicit) If (convKind = ConversionKind.WideningReference OrElse convKind = ConversionKind.NarrowingReference) AndAlso sourceType.IsWellKnownTypeLock() Then ReportDiagnostic(diagnostics, argument.Syntax, ERRID.WRN_ConvertingLock) End If Return New BoundConversion(tree, argument, convKind, CheckOverflow, isExplicit, constantResult, tupleElements, targetType) End Function Private Function CreateConversionForTupleElements( tree As SyntaxNode, sourceType As TypeSymbol, targetType As TypeSymbol, convKind As ConversionKind, isExplicit As Boolean ) As BoundConvertedTupleElements If (convKind And ConversionKind.Tuple) <> 0 Then Dim sourceElementTypes = sourceType.GetNullableUnderlyingTypeOrSelf().GetElementTypesOfTupleOrCompatible() Dim targetElementTypes = targetType.GetNullableUnderlyingTypeOrSelf().GetElementTypesOfTupleOrCompatible() Dim placeholders = ArrayBuilder(Of BoundRValuePlaceholder).GetInstance(sourceElementTypes.Length) Dim converted = ArrayBuilder(Of BoundExpression).GetInstance(sourceElementTypes.Length) For i As Integer = 0 To sourceElementTypes.Length - 1 Dim placeholder = New BoundRValuePlaceholder(tree, sourceElementTypes(i)).MakeCompilerGenerated() placeholders.Add(placeholder) converted.Add(ApplyConversion(tree, targetElementTypes(i), placeholder, isExplicit, BindingDiagnosticBag.Discarded)) Next Return New BoundConvertedTupleElements(tree, placeholders.ToImmutableAndFree(), converted.ToImmutableAndFree()).MakeCompilerGenerated() End If Return Nothing End Function Private Function CreateUserDefinedConversion( tree As SyntaxNode, argument As BoundExpression, convKind As KeyValuePair(Of ConversionKind, MethodSymbol), isExplicit As Boolean, targetType As TypeSymbol, reportArrayLiteralElementNarrowingConversion As Boolean, diagnostics As BindingDiagnosticBag ) As BoundConversion Debug.Assert((convKind.Key And ConversionKind.UserDefined) <> 0 AndAlso convKind.Value IsNot Nothing AndAlso convKind.Value.ParameterCount = 1 AndAlso Not convKind.Value.IsSub AndAlso Not convKind.Value.Parameters(0).IsByRef AndAlso convKind.Value.IsShared) ' Suppress any Option Strict diagnostics. Dim conversionBinder = New OptionStrictOffBinder(Me) Dim argumentSyntax = argument.Syntax Dim originalArgumentType As TypeSymbol = argument.Type Dim inType As TypeSymbol = convKind.Value.Parameters(0).Type Dim outType As TypeSymbol = convKind.Value.ReturnType Dim intermediateConv As ConversionKind Dim inOutConversionFlags As Byte = 0 Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics) If argument.Kind = BoundKind.ArrayLiteral Then ' For array literals, report Option Strict diagnostics for each element when reportArrayLiteralElementNarrowingConversion is true. Dim arrayLiteral = DirectCast(argument, BoundArrayLiteral) Dim arrayLiteralBinder = If(reportArrayLiteralElementNarrowingConversion, Me, conversionBinder) intermediateConv = Conversions.ClassifyArrayLiteralConversion(arrayLiteral, inType, arrayLiteralBinder, useSiteInfo) argument = arrayLiteralBinder.ReclassifyArrayLiteralExpression(SyntaxKind.CTypeKeyword, tree, intermediateConv, isExplicit, arrayLiteral, inType, diagnostics) originalArgumentType = inType Else intermediateConv = Conversions.ClassifyPredefinedConversion(argument, inType, conversionBinder, useSiteInfo) If Not Conversions.IsIdentityConversion(intermediateConv) Then #If DEBUG Then Dim oldArgument = argument #End If argument = conversionBinder.CreatePredefinedConversion(tree, argument, intermediateConv, isExplicit, inType, diagnostics). MakeCompilerGenerated() #If DEBUG Then Debug.Assert(oldArgument IsNot argument AndAlso argument.Kind = BoundKind.Conversion) #End If inOutConversionFlags = 1 End If End If ReportUseSite(diagnostics, tree, convKind.Value) ReportDiagnosticsIfObsoleteOrNotSupported(diagnostics, convKind.Value, tree) Debug.Assert(convKind.Value.IsUserDefinedOperator()) If Me.ContainingMember Is convKind.Value Then ReportDiagnostic(diagnostics, argumentSyntax, ERRID.WRN_RecursiveOperatorCall, convKind.Value) End If argument = New BoundCall(tree, method:=convKind.Value, methodGroupOpt:=Nothing, receiverOpt:=Nothing, arguments:=ImmutableArray.Create(Of BoundExpression)(argument), constantValueOpt:=Nothing, suppressObjectClone:=True, type:=outType).MakeCompilerGenerated() intermediateConv = Conversions.ClassifyPredefinedConversion(argument, targetType, conversionBinder, useSiteInfo) If Not Conversions.IsIdentityConversion(intermediateConv) Then #If DEBUG Then Dim oldArgument = argument #End If argument = conversionBinder.CreatePredefinedConversion(tree, argument, intermediateConv, isExplicit, targetType, diagnostics). MakeCompilerGenerated() #If DEBUG Then Debug.Assert(oldArgument IsNot argument AndAlso argument.Kind = BoundKind.Conversion) #End If inOutConversionFlags = inOutConversionFlags Or CByte(2) End If argument = New BoundUserDefinedConversion(tree, argument, inOutConversionFlags, originalArgumentType).MakeCompilerGenerated() diagnostics.Add(tree, useSiteInfo) Return New BoundConversion(tree, argument, convKind.Key, CheckOverflow, isExplicit, DirectCast(Nothing, ConstantValue), targetType) End Function ''' <summary> ''' Handle expression reclassification, if any applicable. ''' ''' If function returns True, the "argument" parameter has been replaced ''' with result of reclassification (possibly an error node) and appropriate ''' diagnostic, if any, has been reported. ''' ''' If function returns false, the "argument" parameter must be unchanged and no ''' diagnostic should be reported. ''' ''' conversionSemantics can be one of these: ''' SyntaxKind.CTypeKeyword, SyntaxKind.DirectCastKeyword, SyntaxKind.TryCastKeyword ''' </summary> Private Function ReclassifyExpression( ByRef argument As BoundExpression, conversionSemantics As SyntaxKind, tree As SyntaxNode, convKind As ConversionKind, isExplicit As Boolean, targetType As TypeSymbol, diagnostics As BindingDiagnosticBag ) As Boolean Debug.Assert(argument.Kind <> BoundKind.GroupTypeInferenceLambda) Select Case argument.Kind Case BoundKind.Parenthesized If argument.Type Is Nothing AndAlso Not argument.IsNothingLiteral() Then Dim parenthesized = DirectCast(argument, BoundParenthesized) Dim enclosed As BoundExpression = parenthesized.Expression ' Reclassify enclosed expression. If ReclassifyExpression(enclosed, conversionSemantics, enclosed.Syntax, convKind, isExplicit, targetType, diagnostics) Then argument = parenthesized.Update(enclosed, enclosed.Type) Return True End If End If Case BoundKind.UnboundLambda argument = ReclassifyUnboundLambdaExpression(DirectCast(argument, UnboundLambda), conversionSemantics, tree, convKind, isExplicit, targetType, diagnostics) Return True Case BoundKind.QueryLambda argument = ReclassifyQueryLambdaExpression(DirectCast(argument, BoundQueryLambda), conversionSemantics, tree, convKind, isExplicit, targetType, diagnostics) Return True Case BoundKind.LateAddressOfOperator Dim addressOfExpression = DirectCast(argument, BoundLateAddressOfOperator) If targetType.TypeKind <> TypeKind.Delegate AndAlso targetType.TypeKind <> TypeKind.Error Then ' 'AddressOf' expression cannot be converted to '{0}' because '{0}' is not a delegate type. ReportDiagnostic(diagnostics, addressOfExpression.Syntax, ERRID.ERR_AddressOfNotDelegate1, targetType) End If argument = addressOfExpression.Update(addressOfExpression.Binder, addressOfExpression.MemberAccess, targetType) Return True Case BoundKind.AddressOfOperator Dim delegateResolutionResult As DelegateResolutionResult = Nothing Dim addressOfExpression = DirectCast(argument, BoundAddressOfOperator) If addressOfExpression.GetDelegateResolutionResult(targetType, delegateResolutionResult) Then diagnostics.AddRange(delegateResolutionResult.Diagnostics) Dim hasErrors = True If Conversions.ConversionExists(delegateResolutionResult.DelegateConversions) Then Dim reclassifyBinder As Binder ' If conversion is explicit, use Option Strict Off. If isExplicit AndAlso Me.OptionStrict <> VisualBasic.OptionStrict.Off Then reclassifyBinder = New OptionStrictOffBinder(Me) Else reclassifyBinder = Me End If Debug.Assert(Not isExplicit OrElse reclassifyBinder.OptionStrict = VisualBasic.OptionStrict.Off) argument = reclassifyBinder.ReclassifyAddressOf(addressOfExpression, delegateResolutionResult, targetType, diagnostics, isForHandles:=False, warnIfResultOfAsyncMethodIsDroppedDueToRelaxation:=Not isExplicit AndAlso tree.Kind <> SyntaxKind.ObjectCreationExpression) hasErrors = argument.HasErrors Debug.Assert(convKind = delegateResolutionResult.DelegateConversions) End If If argument.Kind <> BoundKind.DelegateCreationExpression Then If conversionSemantics = SyntaxKind.CTypeKeyword Then argument = New BoundConversion(tree, argument, convKind, False, isExplicit, targetType, hasErrors:=hasErrors) ElseIf conversionSemantics = SyntaxKind.DirectCastKeyword Then argument = New BoundDirectCast(tree, argument, convKind, targetType, hasErrors:=hasErrors) ElseIf conversionSemantics = SyntaxKind.TryCastKeyword Then argument = New BoundTryCast(tree, argument, convKind, targetType, hasErrors:=hasErrors) Else Throw ExceptionUtilities.UnexpectedValue(conversionSemantics) End If End If Return True End If Case BoundKind.ArrayLiteral argument = ReclassifyArrayLiteralExpression(conversionSemantics, tree, convKind, isExplicit, DirectCast(argument, BoundArrayLiteral), targetType, diagnostics) Return True Case BoundKind.InterpolatedStringExpression argument = ReclassifyInterpolatedStringExpression(conversionSemantics, tree, convKind, isExplicit, DirectCast(argument, BoundInterpolatedStringExpression), targetType, diagnostics) Return argument.Kind = BoundKind.Conversion Case BoundKind.TupleLiteral Dim literal = DirectCast(argument, BoundTupleLiteral) argument = ReclassifyTupleLiteral(convKind, tree, isExplicit, literal, targetType, diagnostics) Return argument IsNot literal End Select Return False End Function Private Function ReclassifyUnboundLambdaExpression( unboundLambda As UnboundLambda, conversionSemantics As SyntaxKind, tree As SyntaxNode, convKind As ConversionKind, isExplicit As Boolean, targetType As TypeSymbol, diagnostics As BindingDiagnosticBag ) As BoundExpression Dim targetDelegateType As NamedTypeSymbol ' the target delegate type; if targetType is Expression(Of D), then this is D, otherwise targetType or Nothing. Dim delegateInvoke As MethodSymbol If targetType.IsStrictSupertypeOfConcreteDelegate() Then ' covers Object, System.Delegate, System.MulticastDelegate ' Reclassify the lambda as an instance of an Anonymous Delegate. Dim anonymousDelegate As BoundExpression = ReclassifyUnboundLambdaExpression(unboundLambda, diagnostics) #If DEBUG Then Dim anonymousDelegateInfo As KeyValuePair(Of NamedTypeSymbol, ReadOnlyBindingDiagnostic(Of AssemblySymbol)) = unboundLambda.InferredAnonymousDelegate Debug.Assert(anonymousDelegate.Type Is anonymousDelegateInfo.Key) ' If we have errors for the inference, we know that there is no conversion. If Not anonymousDelegateInfo.Value.Diagnostics.IsDefault AndAlso anonymousDelegateInfo.Value.Diagnostics.HasAnyErrors() Then Debug.Assert(Conversions.NoConversion(convKind) AndAlso (convKind And ConversionKind.DelegateRelaxationLevelMask) = 0) Else Debug.Assert(Conversions.NoConversion(convKind) OrElse (convKind And ConversionKind.DelegateRelaxationLevelMask) >= ConversionKind.DelegateRelaxationLevelWideningToNonLambda) End If #End If ' Now convert it to the target type. If conversionSemantics = SyntaxKind.CTypeKeyword Then Return ApplyConversion(tree, targetType, anonymousDelegate, isExplicit, diagnostics) ElseIf conversionSemantics = SyntaxKind.DirectCastKeyword Then Return ApplyDirectCastConversion(tree, anonymousDelegate, targetType, diagnostics) ElseIf conversionSemantics = SyntaxKind.TryCastKeyword Then Return ApplyTryCastConversion(tree, anonymousDelegate, targetType, diagnostics) Else Throw ExceptionUtilities.UnexpectedValue(conversionSemantics) End If Else targetDelegateType = targetType.DelegateOrExpressionDelegate(Me) If targetDelegateType Is Nothing Then Debug.Assert((convKind And ConversionKind.DelegateRelaxationLevelMask) = 0) ReportDiagnostic(diagnostics, unboundLambda.Syntax, ERRID.ERR_LambdaNotDelegate1, targetType) delegateInvoke = Nothing ' No conversion Else delegateInvoke = targetDelegateType.DelegateInvokeMethod If delegateInvoke Is Nothing Then ReportDiagnostic(diagnostics, unboundLambda.Syntax, ERRID.ERR_LambdaNotDelegate1, targetDelegateType) delegateInvoke = Nothing ' No conversion ElseIf ReportDelegateInvokeUseSite(diagnostics, unboundLambda.Syntax, targetDelegateType, delegateInvoke) Then delegateInvoke = Nothing ' No conversion ElseIf unboundLambda.IsInferredDelegateForThisLambda(delegateInvoke.ContainingType) Then Dim inferenceDiagnostics As ReadOnlyBindingDiagnostic(Of AssemblySymbol) = unboundLambda.InferredAnonymousDelegate.Value diagnostics.AddRange(inferenceDiagnostics) If Not inferenceDiagnostics.Diagnostics.IsDefaultOrEmpty AndAlso inferenceDiagnostics.Diagnostics.HasAnyErrors() Then delegateInvoke = Nothing ' No conversion End If End If Debug.Assert(delegateInvoke IsNot Nothing OrElse (convKind And ConversionKind.DelegateRelaxationLevelMask) = 0) End If End If Dim boundLambda As BoundLambda = Nothing If delegateInvoke IsNot Nothing Then boundLambda = unboundLambda.GetBoundLambda(New UnboundLambda.TargetSignature(delegateInvoke)) Debug.Assert(boundLambda IsNot Nothing) If boundLambda Is Nothing Then ' An unlikely case. Debug.Assert((convKind And ConversionKind.DelegateRelaxationLevelMask) = 0) ReportDiagnostic(diagnostics, unboundLambda.Syntax, If(unboundLambda.IsFunctionLambda, ERRID.ERR_LambdaBindingMismatch1, ERRID.ERR_LambdaBindingMismatch2), If(targetDelegateType.TypeKind = TypeKind.Delegate AndAlso targetDelegateType.IsFromCompilation(Me.Compilation), CType(CustomSymbolDisplayFormatter.DelegateSignature(targetDelegateType), Object), CType(targetDelegateType, Object))) End If End If If boundLambda Is Nothing Then Debug.Assert(Conversions.NoConversion(convKind)) Dim errorRecovery As BoundLambda = unboundLambda.BindForErrorRecovery() If conversionSemantics = SyntaxKind.CTypeKeyword Then Return New BoundConversion(tree, errorRecovery, convKind, False, isExplicit, targetType, hasErrors:=True) ElseIf conversionSemantics = SyntaxKind.DirectCastKeyword Then Return New BoundDirectCast(tree, errorRecovery, convKind, targetType, hasErrors:=True) ElseIf conversionSemantics = SyntaxKind.TryCastKeyword Then Return New BoundTryCast(tree, errorRecovery, convKind, targetType, hasErrors:=True) Else Throw ExceptionUtilities.UnexpectedValue(conversionSemantics) End If End If Dim boundLambdaDiagnostics = boundLambda.Diagnostics Debug.Assert((convKind And ConversionKind.DelegateRelaxationLevelMask) >= boundLambda.DelegateRelaxation) Debug.Assert(Conversions.ClassifyMethodConversionForLambdaOrAnonymousDelegate(delegateInvoke, boundLambda.LambdaSymbol, CompoundUseSiteInfo(Of AssemblySymbol).Discarded) = MethodConversionKind.Identity OrElse ((convKind And ConversionKind.DelegateRelaxationLevelMask) <> ConversionKind.DelegateRelaxationLevelNone AndAlso boundLambda.MethodConversionKind <> MethodConversionKind.Identity)) Dim reportedAnError As Boolean = boundLambdaDiagnostics.Diagnostics.HasAnyErrors() diagnostics.AddRange(boundLambdaDiagnostics) Dim relaxationLambdaOpt As BoundLambda = Nothing If (convKind And ConversionKind.DelegateRelaxationLevelMask) = ConversionKind.DelegateRelaxationLevelInvalid AndAlso Not reportedAnError AndAlso Not boundLambda.HasErrors Then ' We don't try to infer return type of a lambda that has both Async and Iterator modifiers, let's suppress the ' signature mismatch error in this case. If unboundLambda.ReturnType IsNot Nothing OrElse unboundLambda.Flags <> (SourceMemberFlags.Async Or SourceMemberFlags.Iterator) Then Dim err As ERRID If unboundLambda.IsFunctionLambda Then err = ERRID.ERR_LambdaBindingMismatch1 Else err = ERRID.ERR_LambdaBindingMismatch2 End If ReportDiagnostic(diagnostics, unboundLambda.Syntax, err, If(targetDelegateType.TypeKind = TypeKind.Delegate AndAlso targetDelegateType.IsFromCompilation(Me.Compilation), CType(CustomSymbolDisplayFormatter.DelegateSignature(targetDelegateType), Object), CType(targetDelegateType, Object))) End If ElseIf Conversions.IsStubRequiredForMethodConversion(boundLambda.MethodConversionKind) Then Debug.Assert(Conversions.IsDelegateRelaxationSupportedFor(boundLambda.MethodConversionKind)) ' Need to produce a stub. ' First, we need to get an Anonymous Delegate of the same shape as the lambdaSymbol. Dim lambdaSymbol As LambdaSymbol = boundLambda.LambdaSymbol Dim anonymousDelegateType As NamedTypeSymbol = ConstructAnonymousDelegateSymbol(unboundLambda, (lambdaSymbol.Parameters.As(Of BoundLambdaParameterSymbol)), lambdaSymbol.ReturnType, diagnostics) ' Second, reclassify the bound lambda as an instance of the Anonymous Delegate. Dim anonymousDelegateInstance = New BoundConversion(tree, boundLambda, ConversionKind.Widening Or ConversionKind.Lambda, False, False, anonymousDelegateType) anonymousDelegateInstance.SetWasCompilerGenerated() ' Third, create a method group representing Invoke method of the instance of the Anonymous Delegate. Dim methodGroup = New BoundMethodGroup(unboundLambda.Syntax, Nothing, ImmutableArray.Create(anonymousDelegateType.DelegateInvokeMethod), LookupResultKind.Good, anonymousDelegateInstance, QualificationKind.QualifiedViaValue) methodGroup.SetWasCompilerGenerated() ' Fourth, create a lambda with the shape of the target delegate that calls the Invoke with appropriate conversions ' and drops parameters and/or return value, if needed, thus performing the relaxation. Dim relaxationBinder As Binder ' If conversion is explicit, use Option Strict Off. If isExplicit AndAlso Me.OptionStrict <> VisualBasic.OptionStrict.Off Then relaxationBinder = New OptionStrictOffBinder(Me) Else relaxationBinder = Me End If Debug.Assert(Not isExplicit OrElse relaxationBinder.OptionStrict = VisualBasic.OptionStrict.Off) relaxationLambdaOpt = relaxationBinder.BuildDelegateRelaxationLambda(unboundLambda.Syntax, delegateInvoke, methodGroup, boundLambda.DelegateRelaxation, isZeroArgumentKnownToBeUsed:=False, warnIfResultOfAsyncMethodIsDroppedDueToRelaxation:=Not isExplicit AndAlso tree.Kind <> SyntaxKind.ObjectCreationExpression, diagnostics:=diagnostics) End If If conversionSemantics = SyntaxKind.CTypeKeyword Then Return New BoundConversion(tree, boundLambda, convKind, False, isExplicit, Nothing, If(relaxationLambdaOpt Is Nothing, Nothing, New BoundRelaxationLambda(tree, relaxationLambdaOpt, receiverPlaceholderOpt:=Nothing).MakeCompilerGenerated()), targetType) ElseIf conversionSemantics = SyntaxKind.DirectCastKeyword Then Return New BoundDirectCast(tree, boundLambda, convKind, relaxationLambdaOpt, targetType) ElseIf conversionSemantics = SyntaxKind.TryCastKeyword Then Return New BoundTryCast(tree, boundLambda, convKind, relaxationLambdaOpt, targetType) Else Throw ExceptionUtilities.UnexpectedValue(conversionSemantics) End If End Function Private Function ReclassifyQueryLambdaExpression( lambda As BoundQueryLambda, conversionSemantics As SyntaxKind, tree As SyntaxNode, convKind As ConversionKind, isExplicit As Boolean, targetType As TypeSymbol, diagnostics As BindingDiagnosticBag ) As BoundExpression Debug.Assert(lambda.Type Is Nothing) ' the target delegate type; if targetType is Expression(Of D), then this is D, otherwise targetType or Nothing. Dim targetDelegateType As NamedTypeSymbol = targetType.DelegateOrExpressionDelegate(Me) If Conversions.NoConversion(convKind) Then If targetType.IsStrictSupertypeOfConcreteDelegate() AndAlso Not targetType.IsObjectType() Then ReportDiagnostic(diagnostics, lambda.Syntax, ERRID.ERR_LambdaNotCreatableDelegate1, targetType) Else If targetDelegateType Is Nothing Then ReportDiagnostic(diagnostics, lambda.Syntax, ERRID.ERR_LambdaNotDelegate1, targetType) Else Dim invoke As MethodSymbol = targetDelegateType.DelegateInvokeMethod If invoke Is Nothing Then ReportDiagnostic(diagnostics, lambda.Syntax, ERRID.ERR_LambdaNotDelegate1, targetDelegateType) ElseIf Not ReportDelegateInvokeUseSite(diagnostics, lambda.Syntax, targetDelegateType, invoke) Then ' Conversion could fail because we couldn't convert body of the lambda ' to the target delegate type. We want to report that error instead of ' lambda signature mismatch. If lambda.LambdaSymbol.ReturnType Is LambdaSymbol.ReturnTypePendingDelegate AndAlso Not invoke.IsSub AndAlso Conversions.FailedDueToQueryLambdaBodyMismatch(convKind) Then lambda = lambda.Update(lambda.LambdaSymbol, lambda.RangeVariables, ApplyImplicitConversion(lambda.Expression.Syntax, invoke.ReturnType, lambda.Expression, diagnostics, If(invoke.ReturnType.IsBooleanType, lambda.ExprIsOperandOfConditionalBranch, False)), exprIsOperandOfConditionalBranch:=False) Else ReportDiagnostic(diagnostics, lambda.Syntax, ERRID.ERR_LambdaBindingMismatch1, targetDelegateType) End If End If End If End If If conversionSemantics = SyntaxKind.CTypeKeyword Then Return New BoundConversion(tree, lambda, convKind, False, isExplicit, targetType, hasErrors:=True).MakeCompilerGenerated() ElseIf conversionSemantics = SyntaxKind.DirectCastKeyword Then Return New BoundDirectCast(tree, lambda, convKind, targetType, hasErrors:=True).MakeCompilerGenerated() ElseIf conversionSemantics = SyntaxKind.TryCastKeyword Then Return New BoundTryCast(tree, lambda, convKind, targetType, hasErrors:=True).MakeCompilerGenerated() End If Throw ExceptionUtilities.UnexpectedValue(conversionSemantics) End If Dim delegateInvoke As MethodSymbol = targetDelegateType.DelegateInvokeMethod For Each delegateParam As ParameterSymbol In delegateInvoke.Parameters If delegateParam.IsByRef OrElse delegateParam.OriginalDefinition.Type.IsTypeParameter() Then Dim restrictedType As TypeSymbol = Nothing If delegateParam.Type.IsRestrictedTypeOrArrayType(restrictedType) Then ReportDiagnostic(diagnostics, lambda.LambdaSymbol.Parameters(delegateParam.Ordinal).GetFirstLocation(), ERRID.ERR_RestrictedType1, restrictedType) End If End If Next Dim delegateReturnType As TypeSymbol = delegateInvoke.ReturnType If delegateInvoke.OriginalDefinition.ReturnType.IsTypeParameter() Then Dim restrictedType As TypeSymbol = Nothing If delegateReturnType.IsRestrictedTypeOrArrayType(restrictedType) Then Dim location As SyntaxNode If lambda.Expression.Kind = BoundKind.RangeVariableAssignment Then location = DirectCast(lambda.Expression, BoundRangeVariableAssignment).Value.Syntax Else location = lambda.Expression.Syntax End If ReportDiagnostic(diagnostics, location, ERRID.ERR_RestrictedType1, restrictedType) End If End If If lambda.LambdaSymbol.ReturnType Is LambdaSymbol.ReturnTypePendingDelegate Then lambda = lambda.Update(lambda.LambdaSymbol, lambda.RangeVariables, ApplyImplicitConversion(lambda.Expression.Syntax, delegateReturnType, lambda.Expression, diagnostics, If(delegateReturnType.IsBooleanType(), lambda.ExprIsOperandOfConditionalBranch, False)), exprIsOperandOfConditionalBranch:=False) Else lambda = lambda.Update(lambda.LambdaSymbol, lambda.RangeVariables, lambda.Expression, exprIsOperandOfConditionalBranch:=False) End If If conversionSemantics = SyntaxKind.CTypeKeyword Then Return New BoundConversion(tree, lambda, convKind, False, isExplicit, targetType).MakeCompilerGenerated() ElseIf conversionSemantics = SyntaxKind.DirectCastKeyword Then Return New BoundDirectCast(tree, lambda, convKind, targetType).MakeCompilerGenerated() ElseIf conversionSemantics = SyntaxKind.TryCastKeyword Then Return New BoundTryCast(tree, lambda, convKind, targetType).MakeCompilerGenerated() End If Throw ExceptionUtilities.UnexpectedValue(conversionSemantics) End Function Private Function ReclassifyInterpolatedStringExpression(conversionSemantics As SyntaxKind, tree As SyntaxNode, convKind As ConversionKind, isExplicit As Boolean, node As BoundInterpolatedStringExpression, targetType As TypeSymbol, diagnostics As BindingDiagnosticBag) As BoundExpression If (convKind And ConversionKind.InterpolatedString) = ConversionKind.InterpolatedString Then Debug.Assert(targetType.Equals(Compilation.GetWellKnownType(WellKnownType.System_IFormattable)) OrElse targetType.Equals(Compilation.GetWellKnownType(WellKnownType.System_FormattableString))) Return New BoundConversion(tree, BindUnconvertedInterpolatedStringToFormattable(tree, node, targetType, diagnostics), ConversionKind.InterpolatedString, False, isExplicit, targetType) End If Return node End Function Private Function ReclassifyTupleLiteral( convKind As ConversionKind, tree As SyntaxNode, isExplicit As Boolean, sourceTuple As BoundTupleLiteral, destination As TypeSymbol, diagnostics As BindingDiagnosticBag) As BoundExpression ' We have a successful tuple conversion rather than producing a separate conversion node ' which is a conversion on top of a tuple literal, tuple conversion is an element-wise conversion of arguments. Dim isNullableTupleConversion = (convKind And ConversionKind.Nullable) <> 0 Debug.Assert(Not isNullableTupleConversion OrElse destination.IsNullableType()) Dim targetType = destination If isNullableTupleConversion Then targetType = destination.GetNullableUnderlyingType() End If Dim arguments = sourceTuple.Arguments If Not targetType.IsTupleOrCompatibleWithTupleOfCardinality(arguments.Length) Then Return sourceTuple End If If targetType.IsTupleType Then Dim destTupleType = DirectCast(targetType, TupleTypeSymbol) TupleTypeSymbol.ReportNamesMismatchesIfAny(targetType, sourceTuple, diagnostics) ' do not lose the original element names in the literal if different from names in the target ' Come back to this, what about locations? (https:'github.com/dotnet/roslyn/issues/11013) targetType = destTupleType.WithElementNames(sourceTuple.ArgumentNamesOpt) End If Dim convertedArguments = ArrayBuilder(Of BoundExpression).GetInstance(arguments.Length) Dim targetElementTypes As ImmutableArray(Of TypeSymbol) = targetType.GetElementTypesOfTupleOrCompatible() Debug.Assert(targetElementTypes.Length = arguments.Length, "converting a tuple literal to incompatible type?") For i As Integer = 0 To arguments.Length - 1 Dim argument = arguments(i) Dim destType = targetElementTypes(i) convertedArguments.Add(ApplyConversion(argument.Syntax, destType, argument, isExplicit, diagnostics)) Next Dim result As BoundExpression = New BoundConvertedTupleLiteral( sourceTuple.Syntax, sourceTuple.Type, convertedArguments.ToImmutableAndFree(), targetType) If Not TypeSymbol.Equals(sourceTuple.Type, destination, TypeCompareKind.ConsiderEverything) AndAlso convKind <> Nothing Then ' literal cast is applied to the literal result = New BoundConversion(sourceTuple.Syntax, result, convKind, checked:=False, explicitCastInCode:=isExplicit, type:=destination) End If ' If we had a cast in the code, keep conversion in the tree. ' even though the literal is already converted to the target type. If isExplicit Then result = New BoundConversion( tree, result, ConversionKind.Identity, checked:=False, explicitCastInCode:=isExplicit, type:=destination) End If Return result End Function Private Sub WarnOnNarrowingConversionBetweenSealedClassAndAnInterface( convKind As ConversionKind, location As SyntaxNode, sourceType As TypeSymbol, targetType As TypeSymbol, diagnostics As BindingDiagnosticBag ) If Conversions.IsNarrowingConversion(convKind) Then Dim interfaceType As TypeSymbol = Nothing Dim classType As NamedTypeSymbol = Nothing If sourceType.IsInterfaceType() Then If targetType.IsClassType() Then interfaceType = sourceType classType = DirectCast(targetType, NamedTypeSymbol) End If ElseIf sourceType.IsClassType() AndAlso targetType.IsInterfaceType() Then interfaceType = targetType classType = DirectCast(sourceType, NamedTypeSymbol) End If Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics) If classType IsNot Nothing AndAlso interfaceType IsNot Nothing AndAlso classType.IsNotInheritable AndAlso Not classType.IsComImport() AndAlso Not Conversions.IsWideningConversion(Conversions.ClassifyDirectCastConversion(classType, interfaceType, useSiteInfo)) Then ' Report specific warning if converting IEnumerable(Of XElement) to String. If (targetType.SpecialType = SpecialType.System_String) AndAlso IsIEnumerableOfXElement(sourceType, useSiteInfo) Then ReportDiagnostic(diagnostics, location, ERRID.WRN_UseValueForXmlExpression3, sourceType, targetType, sourceType) Else ReportDiagnostic(diagnostics, location, ERRID.WRN_InterfaceConversion2, sourceType, targetType) End If End If diagnostics.AddDependencies(useSiteInfo) End If End Sub Private Shared Sub WarnOnLockConversion(sourceType As TypeSymbol, syntax As SyntaxNode, diagnostics As BindingDiagnosticBag) If sourceType IsNot Nothing AndAlso sourceType.IsWellKnownTypeLock() Then ReportDiagnostic(diagnostics, syntax, ERRID.WRN_ConvertingLock) End If End Sub Private Function IsIEnumerableOfXElement(type As TypeSymbol, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)) As Boolean Return type.IsOrImplementsIEnumerableOfXElement(Compilation, useSiteInfo) End Function Private Sub ReportNoConversionError( location As SyntaxNode, sourceType As TypeSymbol, targetType As TypeSymbol, diagnostics As BindingDiagnosticBag, Optional copybackConversionParamName As String = Nothing ) If sourceType.IsArrayType() AndAlso targetType.IsArrayType() Then Dim sourceArray = DirectCast(sourceType, ArrayTypeSymbol) Dim targetArray = DirectCast(targetType, ArrayTypeSymbol) Dim sourceElement = sourceArray.ElementType Dim targetElement = targetArray.ElementType If sourceArray.Rank <> targetArray.Rank Then ReportDiagnostic(diagnostics, location, ERRID.ERR_ConvertArrayRankMismatch2, sourceType, targetType) ElseIf sourceArray.IsSZArray <> targetArray.IsSZArray Then ReportDiagnostic(diagnostics, location, ERRID.ERR_TypeMismatch2, sourceType, targetType) ElseIf Not (sourceElement.IsErrorType() OrElse targetElement.IsErrorType()) Then Dim elemConv = Conversions.ClassifyDirectCastConversion(sourceElement, targetElement, CompoundUseSiteInfo(Of AssemblySymbol).Discarded) If Not Conversions.IsIdentityConversion(elemConv) AndAlso (targetElement.IsObjectType() OrElse targetElement.SpecialType = SpecialType.System_ValueType) AndAlso Not sourceElement.IsReferenceType() Then ReportDiagnostic(diagnostics, location, ERRID.ERR_ConvertObjectArrayMismatch3, sourceType, targetType, sourceElement) ElseIf Not Conversions.IsIdentityConversion(elemConv) AndAlso Not (Conversions.IsWideningConversion(elemConv) AndAlso (elemConv And (ConversionKind.Reference Or ConversionKind.Value Or ConversionKind.TypeParameter)) <> 0) Then ReportDiagnostic(diagnostics, location, ERRID.ERR_ConvertArrayMismatch4, sourceType, targetType, sourceElement, targetElement) Else ReportDiagnostic(diagnostics, location, ERRID.ERR_TypeMismatch2, sourceType, targetType) End If End If ElseIf sourceType.IsDateTimeType() AndAlso targetType.IsDoubleType() Then ReportDiagnostic(diagnostics, location, ERRID.ERR_DateToDoubleConversion) ElseIf targetType.IsDateTimeType() AndAlso sourceType.IsDoubleType() Then ReportDiagnostic(diagnostics, location, ERRID.ERR_DoubleToDateConversion) ElseIf targetType.IsCharType() AndAlso sourceType.IsIntegralType() Then ReportDiagnostic(diagnostics, location, ERRID.ERR_IntegralToCharTypeMismatch1, sourceType) ElseIf sourceType.IsCharType() AndAlso targetType.IsIntegralType() Then ReportDiagnostic(diagnostics, location, ERRID.ERR_CharToIntegralTypeMismatch1, targetType) ElseIf copybackConversionParamName IsNot Nothing Then ReportDiagnostic(diagnostics, location, ERRID.ERR_CopyBackTypeMismatch3, copybackConversionParamName, sourceType, targetType) ElseIf sourceType.IsInterfaceType() AndAlso targetType.IsValueType() AndAlso IsIEnumerableOfXElement(sourceType, CompoundUseSiteInfo(Of AssemblySymbol).Discarded) Then ReportDiagnostic(diagnostics, location, ERRID.ERR_TypeMismatchForXml3, sourceType, targetType, sourceType) Else ReportDiagnostic(diagnostics, location, ERRID.ERR_TypeMismatch2, sourceType, targetType) End If End Sub End Class End Namespace