/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Binding/Binder_Delegates.vb
1 293 строки
73 KB
Fred Silberberg
Do not resolve diagnostics early during attribute binding (#71140)
15 дек 2023, 22:36
Не верифицирован
15 дек 2023, 22:36
38f6bcf
Код
Авторство
О чём код?
' 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.PooledObjects Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports TypeKind = Microsoft.CodeAnalysis.TypeKind Namespace Microsoft.CodeAnalysis.VisualBasic Partial Friend Class Binder ''' <summary> ''' Structure is used to store all information which is needed to construct and classify a Delegate creation ''' expression later on. ''' </summary> Friend Structure DelegateResolutionResult ' we store the DelegateConversions although it could be derived from MethodConversions to improve performance Public ReadOnly DelegateConversions As ConversionKind Public ReadOnly Target As MethodSymbol Public ReadOnly MethodConversions As MethodConversionKind Public ReadOnly Diagnostics As ReadOnlyBindingDiagnostic(Of AssemblySymbol) Public Sub New( DelegateConversions As ConversionKind, Target As MethodSymbol, MethodConversions As MethodConversionKind, Diagnostics As ReadOnlyBindingDiagnostic(Of AssemblySymbol) ) Me.DelegateConversions = DelegateConversions Me.Target = Target Me.Diagnostics = Diagnostics Me.MethodConversions = MethodConversions End Sub End Structure ''' <summary> ''' Binds the AddressOf expression. ''' </summary> ''' <param name="node">The AddressOf expression node.</param> ''' <param name="diagnostics">The diagnostics.</param><returns></returns> Private Function BindAddressOfExpression(node As VisualBasicSyntaxNode, diagnostics As BindingDiagnosticBag) As BoundExpression Dim addressOfSyntax = DirectCast(node, UnaryExpressionSyntax) Dim boundOperand = BindExpression(addressOfSyntax.Operand, isInvocationOrAddressOf:=True, diagnostics:=diagnostics, isOperandOfConditionalBranch:=False, eventContext:=False) If boundOperand.Kind = BoundKind.LateMemberAccess Then Return New BoundLateAddressOfOperator(node, Me, DirectCast(boundOperand, BoundLateMemberAccess), boundOperand.Type) End If ' only accept MethodGroups as operands. More detailed checks (e.g. for Constructors follow later) If boundOperand.Kind <> BoundKind.MethodGroup Then If Not boundOperand.HasErrors Then ReportDiagnostic(diagnostics, addressOfSyntax.Operand, ERRID.ERR_AddressOfOperandNotMethod) End If Return BadExpression(addressOfSyntax, boundOperand, LookupResultKind.NotAValue, ErrorTypeSymbol.UnknownResultType) End If Dim hasErrors As Boolean = False Dim group = DirectCast(boundOperand, BoundMethodGroup) If IsGroupOfConstructors(group) Then ReportDiagnostic(diagnostics, addressOfSyntax.Operand, ERRID.ERR_InvalidConstructorCall) hasErrors = True End If Return New BoundAddressOfOperator(node, Me, diagnostics.AccumulatesDependencies, group, hasErrors) End Function ''' <summary> ''' Binds the delegate creation expression. ''' This comes in form of e.g. ''' Dim del as new DelegateType(AddressOf methodName) ''' </summary> ''' <param name="delegateType">Type of the delegate.</param> ''' <param name="argumentListOpt">The argument list.</param> ''' <param name="node">Syntax node to attach diagnostics to in case the argument list is nothing.</param> ''' <param name="diagnostics">The diagnostics.</param><returns></returns> Private Function BindDelegateCreationExpression( delegateType As TypeSymbol, argumentListOpt As ArgumentListSyntax, node As VisualBasicSyntaxNode, diagnostics As BindingDiagnosticBag ) As BoundExpression Dim boundFirstArgument As BoundExpression = Nothing Dim argumentCount = 0 If argumentListOpt IsNot Nothing Then argumentCount = argumentListOpt.Arguments.Count End If Dim hadErrorsInFirstArgument = False ' a delegate creation expression should have exactly one argument. If argumentCount > 0 Then Dim argumentSyntax = argumentListOpt.Arguments(0) Dim expressionSyntax As ExpressionSyntax = Nothing ' a delegate creation expression does not care if what the name of a named argument ' was. Just take whatever was passed. If argumentSyntax.Kind = SyntaxKind.SimpleArgument Then expressionSyntax = argumentSyntax.GetExpression() End If ' omitted argument will leave expressionSyntax as nothing which means no binding, which is fine. If expressionSyntax IsNot Nothing Then If expressionSyntax.Kind = SyntaxKind.AddressOfExpression Then boundFirstArgument = BindAddressOfExpression(expressionSyntax, diagnostics) ElseIf expressionSyntax.IsLambdaExpressionSyntax() Then ' this covers the legal cases for SyntaxKind.MultiLineFunctionLambdaExpression, ' SyntaxKind.SingleLineFunctionLambdaExpression, SyntaxKind.MultiLineSubLambdaExpression and ' SyntaxKind.SingleLineSubLambdaExpression, as well as all the other invalid ones. boundFirstArgument = BindExpression(expressionSyntax, diagnostics) End If If boundFirstArgument IsNot Nothing Then hadErrorsInFirstArgument = boundFirstArgument.HasErrors Debug.Assert(boundFirstArgument.Kind = BoundKind.BadExpression OrElse boundFirstArgument.Kind = BoundKind.LateAddressOfOperator OrElse boundFirstArgument.Kind = BoundKind.AddressOfOperator OrElse boundFirstArgument.Kind = BoundKind.UnboundLambda) If argumentCount = 1 Then boundFirstArgument = ApplyImplicitConversion(node, delegateType, boundFirstArgument, diagnostics:=diagnostics) If boundFirstArgument.Syntax IsNot node Then ' We must have a bound node that corresponds to that syntax node for GetSemanticInfo. ' Insert an identity conversion if necessary. Debug.Assert(boundFirstArgument.Kind <> BoundKind.Conversion, "Associated wrong node with conversion?") boundFirstArgument = New BoundConversion(node, boundFirstArgument, ConversionKind.Identity, CheckOverflow, True, delegateType) ElseIf boundFirstArgument.Kind = BoundKind.Conversion Then Debug.Assert(Not boundFirstArgument.WasCompilerGenerated) Dim boundConversion = DirectCast(boundFirstArgument, BoundConversion) boundFirstArgument = boundConversion.Update(boundConversion.Operand, boundConversion.ConversionKind, boundConversion.Checked, True, ' ExplicitCastInCode boundConversion.ConstantValueOpt, boundConversion.ExtendedInfoOpt, boundConversion.Type) End If Return boundFirstArgument End If End If Else boundFirstArgument = New BoundBadExpression(argumentSyntax, LookupResultKind.Empty, ImmutableArray(Of Symbol).Empty, ImmutableArray(Of BoundExpression).Empty, ErrorTypeSymbol.UnknownResultType, hasErrors:=True) End If End If Dim boundArguments(argumentCount - 1) As BoundExpression If boundFirstArgument IsNot Nothing Then boundFirstArgument = MakeRValueAndIgnoreDiagnostics(boundFirstArgument) boundArguments(0) = boundFirstArgument End If ' bind all arguments and ignore all diagnostics. These bound nodes will be passed to ' a BoundBadNode For argumentIndex = If(boundFirstArgument Is Nothing, 0, 1) To argumentCount - 1 Dim expressionSyntax As ExpressionSyntax = Nothing Dim argumentSyntax = argumentListOpt.Arguments(argumentIndex) If argumentSyntax.Kind = SyntaxKind.SimpleArgument Then expressionSyntax = argumentSyntax.GetExpression() End If If expressionSyntax IsNot Nothing Then boundArguments(argumentIndex) = BindValue(expressionSyntax, BindingDiagnosticBag.Discarded) Else boundArguments(argumentIndex) = New BoundBadExpression(argumentSyntax, LookupResultKind.Empty, ImmutableArray(Of Symbol).Empty, ImmutableArray(Of BoundExpression).Empty, ErrorTypeSymbol.UnknownResultType, hasErrors:=True) End If Next ' the default error message in delegate creations if the passed arguments are empty or not a addressOf ' should be ERRID.ERR_NoDirectDelegateConstruction1 ' if binding an AddressOf expression caused diagnostics these should be shown instead If Not hadErrorsInFirstArgument OrElse argumentCount <> 1 Then ReportDiagnostic(diagnostics, If(argumentListOpt, node), ERRID.ERR_NoDirectDelegateConstruction1, delegateType) End If Return BadExpression(node, ImmutableArray.Create(boundArguments), delegateType) End Function ''' <summary> ''' Resolves the target method for the delegate and classifies the conversion ''' </summary> ''' <param name="addressOfExpression">The bound AddressOf expression itself.</param> ''' <param name="targetType">The delegate type to assign the result of the AddressOf operator to.</param> ''' <returns></returns> Friend Shared Function InterpretDelegateBinding( addressOfExpression As BoundAddressOfOperator, targetType As TypeSymbol, isForHandles As Boolean ) As DelegateResolutionResult Debug.Assert(targetType IsNot Nothing) Dim diagnostics = BindingDiagnosticBag.GetInstance(withDiagnostics:=True, addressOfExpression.WithDependencies) Dim result As OverloadResolution.OverloadResolutionResult = Nothing Dim fromMethod As MethodSymbol = Nothing Dim syntaxTree = addressOfExpression.Syntax Dim methodConversions As MethodConversionKind = MethodConversionKind.Identity ' must be a delegate, and also a concrete delegate If targetType.SpecialType = SpecialType.System_Delegate OrElse targetType.SpecialType = SpecialType.System_MulticastDelegate Then ' 'AddressOf' expression cannot be converted to '{0}' because type '{0}' is declared 'MustInherit' and cannot be created. ReportDiagnostic(diagnostics, syntaxTree, ERRID.ERR_AddressOfNotCreatableDelegate1, targetType) methodConversions = methodConversions Or MethodConversionKind.Error_Unspecified ElseIf targetType.TypeKind <> TypeKind.Delegate Then ' 'AddressOf' expression cannot be converted to '{0}' because '{0}' is not a delegate type. If targetType.TypeKind <> TypeKind.Error Then ReportDiagnostic(diagnostics, syntaxTree, ERRID.ERR_AddressOfNotDelegate1, targetType) End If methodConversions = methodConversions Or MethodConversionKind.Error_Unspecified Else Dim delegateInvoke = DirectCast(targetType, NamedTypeSymbol).DelegateInvokeMethod If delegateInvoke IsNot Nothing Then If ReportDelegateInvokeUseSite(diagnostics, syntaxTree, targetType, delegateInvoke) Then methodConversions = methodConversions Or MethodConversionKind.Error_Unspecified Else ' todo(rbeckers) if (IsLateReference(addressOfExpression)) Dim matchingMethod As KeyValuePair(Of MethodSymbol, MethodConversionKind) = ResolveMethodForDelegateInvokeFullAndRelaxed( addressOfExpression, delegateInvoke, False, diagnostics) fromMethod = matchingMethod.Key methodConversions = matchingMethod.Value End If Else ReportDiagnostic(diagnostics, syntaxTree, ERRID.ERR_UnsupportedMethod1, targetType) methodConversions = methodConversions Or MethodConversionKind.Error_Unspecified End If End If ' show diagnostics if the an instance method is used in a shared context. If fromMethod IsNot Nothing Then ' Generate an error, but continue processing If addressOfExpression.Binder.CheckSharedSymbolAccess(addressOfExpression.Syntax, fromMethod.IsShared, addressOfExpression.MethodGroup.ReceiverOpt, addressOfExpression.MethodGroup.QualificationKind, diagnostics) Then methodConversions = methodConversions Or MethodConversionKind.Error_Unspecified End If End If ' TODO: Check boxing of restricted types, report ERRID_RestrictedConversion1 and continue. Dim receiver As BoundExpression = addressOfExpression.MethodGroup.ReceiverOpt If fromMethod IsNot Nothing Then If fromMethod.IsMustOverride AndAlso receiver IsNot Nothing AndAlso (receiver.IsMyBaseReference OrElse receiver.IsMyClassReference) Then ' Generate an error, but continue processing ReportDiagnostic(diagnostics, addressOfExpression.MethodGroup.Syntax, If(receiver.IsMyBaseReference, ERRID.ERR_MyBaseAbstractCall1, ERRID.ERR_MyClassAbstractCall1), fromMethod) methodConversions = methodConversions Or MethodConversionKind.Error_Unspecified End If If Not fromMethod.IsShared AndAlso fromMethod.ContainingType.IsNullableType AndAlso Not fromMethod.IsOverrides Then Dim addressOfSyntax As SyntaxNode = addressOfExpression.Syntax Dim addressOfExpressionSyntax = DirectCast(addressOfExpression.Syntax, UnaryExpressionSyntax) If (addressOfExpressionSyntax IsNot Nothing) Then addressOfSyntax = addressOfExpressionSyntax.Operand End If ' Generate an error, but continue processing ReportDiagnostic(diagnostics, addressOfSyntax, ERRID.ERR_AddressOfNullableMethod, fromMethod.ContainingType, SyntaxFacts.GetText(SyntaxKind.AddressOfKeyword)) ' There's no real need to set MethodConversionKind.Error because there are no overloads of the same method where one ' may be legal to call because it's shared and the other's not. ' However to be future proof, we set it regardless. methodConversions = methodConversions Or MethodConversionKind.Error_Unspecified End If addressOfExpression.Binder.ReportDiagnosticsIfObsoleteOrNotSupported(diagnostics, fromMethod, addressOfExpression.MethodGroup.Syntax) End If Dim delegateConversions As ConversionKind = Conversions.DetermineDelegateRelaxationLevel(methodConversions) If (delegateConversions And ConversionKind.DelegateRelaxationLevelInvalid) <> ConversionKind.DelegateRelaxationLevelInvalid Then If Conversions.IsNarrowingMethodConversion(methodConversions, isForAddressOf:=Not isForHandles) Then delegateConversions = delegateConversions Or ConversionKind.Narrowing Else delegateConversions = delegateConversions Or ConversionKind.Widening End If End If Return New DelegateResolutionResult(delegateConversions, fromMethod, methodConversions, diagnostics.ToReadOnlyAndFree()) End Function Friend Shared Function ReportDelegateInvokeUseSite( diagBag As BindingDiagnosticBag, syntax As SyntaxNode, delegateType As TypeSymbol, invoke As MethodSymbol ) As Boolean Debug.Assert(delegateType IsNot Nothing) Debug.Assert(invoke IsNot Nothing) Dim useSiteInfo As UseSiteInfo(Of AssemblySymbol) = invoke.GetUseSiteInfo() If useSiteInfo.DiagnosticInfo?.Code = ERRID.ERR_UnsupportedMethod1 Then useSiteInfo = New UseSiteInfo(Of AssemblySymbol)(ErrorFactory.ErrorInfo(ERRID.ERR_UnsupportedMethod1, delegateType)) End If Return diagBag.Add(useSiteInfo, syntax) End Function ''' <summary> ''' Resolves the method for delegate invoke with all or relaxed arguments / return types. It also determines ''' the method conversion kind. ''' </summary> ''' <param name="addressOfExpression">The AddressOf expression.</param> ''' <param name="toMethod">The delegate invoke method.</param> ''' <param name="ignoreMethodReturnType">Ignore method's return type for the purpose of calculating 'methodConversions'.</param> ''' <param name="diagnostics">The diagnostics.</param> ''' <returns>The resolved method if any.</returns> Friend Shared Function ResolveMethodForDelegateInvokeFullAndRelaxed( addressOfExpression As BoundAddressOfOperator, toMethod As MethodSymbol, ignoreMethodReturnType As Boolean, diagnostics As BindingDiagnosticBag ) As KeyValuePair(Of MethodSymbol, MethodConversionKind) Dim argumentDiagnostics = BindingDiagnosticBag.GetInstance(diagnostics) Dim couldTryZeroArgumentRelaxation As Boolean = True Dim matchingMethod As KeyValuePair(Of MethodSymbol, MethodConversionKind) = ResolveMethodForDelegateInvokeFullOrRelaxed( addressOfExpression, toMethod, ignoreMethodReturnType, argumentDiagnostics, useZeroArgumentRelaxation:=False, couldTryZeroArgumentRelaxation:=couldTryZeroArgumentRelaxation) ' If there have been parameters and if there was no ambiguous match before, try zero argument relaxation. If matchingMethod.Key Is Nothing AndAlso couldTryZeroArgumentRelaxation Then Dim zeroArgumentDiagnostics = BindingDiagnosticBag.GetInstance(diagnostics) Dim argumentMatchingMethod = matchingMethod matchingMethod = ResolveMethodForDelegateInvokeFullOrRelaxed( addressOfExpression, toMethod, ignoreMethodReturnType, zeroArgumentDiagnostics, useZeroArgumentRelaxation:=True, couldTryZeroArgumentRelaxation:=couldTryZeroArgumentRelaxation) ' if zero relaxation did not find something, we'll report the diagnostics of the ' non zero relaxation try, else the diagnostics of the zero argument relaxation. If matchingMethod.Key Is Nothing Then diagnostics.AddRange(argumentDiagnostics) matchingMethod = argumentMatchingMethod Else diagnostics.AddRange(zeroArgumentDiagnostics) End If zeroArgumentDiagnostics.Free() Else diagnostics.AddRange(argumentDiagnostics) End If argumentDiagnostics.Free() ' check that there's not method returned if there is no conversion. Debug.Assert(matchingMethod.Key Is Nothing OrElse (matchingMethod.Value And MethodConversionKind.AllErrorReasons) = 0) Return matchingMethod End Function ''' <summary> ''' Resolves the method for delegate invoke with all or relaxed arguments / return types. It also determines ''' the method conversion kind. ''' </summary> ''' <param name="addressOfExpression">The AddressOf expression.</param> ''' <param name="toMethod">The delegate invoke method.</param> ''' <param name="ignoreMethodReturnType">Ignore method's return type for the purpose of calculating 'methodConversions'.</param> ''' <param name="diagnostics">The diagnostics.</param> ''' <param name="useZeroArgumentRelaxation">if set to <c>true</c> use zero argument relaxation.</param> ''' <returns>The resolved method if any.</returns> Private Shared Function ResolveMethodForDelegateInvokeFullOrRelaxed( addressOfExpression As BoundAddressOfOperator, toMethod As MethodSymbol, ignoreMethodReturnType As Boolean, diagnostics As BindingDiagnosticBag, useZeroArgumentRelaxation As Boolean, ByRef couldTryZeroArgumentRelaxation As Boolean ) As KeyValuePair(Of MethodSymbol, MethodConversionKind) Dim boundArguments = ImmutableArray(Of BoundExpression).Empty If Not useZeroArgumentRelaxation Then ' build array of bound expressions for overload resolution (BoundLocal is easy to create) Dim toMethodParameters = toMethod.Parameters Dim parameterCount = toMethodParameters.Length If parameterCount > 0 Then Dim boundParameterArguments(parameterCount - 1) As BoundExpression Dim argumentIndex As Integer = 0 Dim syntaxTree As SyntaxTree Dim addressOfSyntax = addressOfExpression.Syntax syntaxTree = addressOfExpression.Binder.SyntaxTree For Each parameter In toMethodParameters Dim parameterType = parameter.Type Dim tempParamSymbol = New SynthesizedLocal(toMethod, parameterType, SynthesizedLocalKind.LoweringTemp) ' TODO: Switch to using BoundValuePlaceholder, but we need it to be able to appear ' as an LValue in case of a ByRef parameter. Dim tempBoundParameter As BoundExpression = New BoundLocal(addressOfSyntax, tempParamSymbol, parameterType) ' don't treat ByVal parameters as lvalues in the following OverloadResolution If Not parameter.IsByRef Then tempBoundParameter = tempBoundParameter.MakeRValue() End If boundParameterArguments(argumentIndex) = tempBoundParameter argumentIndex += 1 Next boundArguments = boundParameterArguments.AsImmutableOrNull() Else couldTryZeroArgumentRelaxation = False End If End If Dim delegateReturnType As TypeSymbol Dim delegateReturnTypeReferenceBoundNode As BoundNode If ignoreMethodReturnType Then ' Keep them Nothing such that the delegate's return type won't be taken part of in overload resolution ' when we are inferring the return type. delegateReturnType = Nothing delegateReturnTypeReferenceBoundNode = Nothing Else delegateReturnType = toMethod.ReturnType delegateReturnTypeReferenceBoundNode = addressOfExpression End If ' Let's go through overload resolution, pretending that Option Strict is Off and see if it succeeds. Dim resolutionBinder As Binder If addressOfExpression.Binder.OptionStrict <> VisualBasic.OptionStrict.Off Then resolutionBinder = New OptionStrictOffBinder(addressOfExpression.Binder) Else resolutionBinder = addressOfExpression.Binder End If Debug.Assert(resolutionBinder.OptionStrict = VisualBasic.OptionStrict.Off) Dim useSiteInfo = addressOfExpression.Binder.GetNewCompoundUseSiteInfo(diagnostics) Dim resolutionResult = OverloadResolution.MethodInvocationOverloadResolution( addressOfExpression.MethodGroup, boundArguments, Nothing, resolutionBinder, includeEliminatedCandidates:=False, delegateReturnType:=delegateReturnType, delegateReturnTypeReferenceBoundNode:=delegateReturnTypeReferenceBoundNode, lateBindingIsAllowed:=False, callerInfoOpt:=Nothing, useSiteInfo:=useSiteInfo) If diagnostics.Add(addressOfExpression.MethodGroup, useSiteInfo) Then couldTryZeroArgumentRelaxation = False If addressOfExpression.MethodGroup.ResultKind <> LookupResultKind.Inaccessible Then ' Suppress additional diagnostics diagnostics = BindingDiagnosticBag.Discarded End If End If Dim addressOfMethodGroup = addressOfExpression.MethodGroup If resolutionResult.BestResult.HasValue Then Return ValidateMethodForDelegateInvoke( addressOfExpression, resolutionResult.BestResult.Value, toMethod, ignoreMethodReturnType, useZeroArgumentRelaxation, diagnostics) End If ' Overload Resolution didn't find a match If resolutionResult.Candidates.Length = 0 Then resolutionResult = OverloadResolution.MethodInvocationOverloadResolution( addressOfMethodGroup, boundArguments, Nothing, resolutionBinder, includeEliminatedCandidates:=True, delegateReturnType:=delegateReturnType, delegateReturnTypeReferenceBoundNode:=delegateReturnTypeReferenceBoundNode, lateBindingIsAllowed:=False, callerInfoOpt:=Nothing, useSiteInfo:=useSiteInfo) End If Dim bestCandidates = ArrayBuilder(Of OverloadResolution.CandidateAnalysisResult).GetInstance() Dim bestSymbols = ImmutableArray(Of Symbol).Empty Dim commonReturnType As TypeSymbol = GetSetOfTheBestCandidates(resolutionResult, bestCandidates, bestSymbols) Debug.Assert(bestCandidates.Count > 0 AndAlso bestCandidates.Count > 0) Dim bestCandidatesState As OverloadResolution.CandidateAnalysisResultState = bestCandidates(0).State If bestCandidatesState = VisualBasic.OverloadResolution.CandidateAnalysisResultState.Applicable Then ' if there is an applicable candidate in the list, we know it must be an ambiguous match ' (or there are more applicable candidates in this list), otherwise this would have been ' the best match. Debug.Assert(bestCandidates.Count > 1 AndAlso bestSymbols.Length > 1) ' there are multiple candidates, so it ambiguous and zero argument relaxation will not be tried, ' unless the candidates require narrowing. If Not bestCandidates(0).RequiresNarrowingConversion Then couldTryZeroArgumentRelaxation = False End If End If If bestSymbols.Length = 1 AndAlso (bestCandidatesState = OverloadResolution.CandidateAnalysisResultState.ArgumentCountMismatch OrElse bestCandidatesState = OverloadResolution.CandidateAnalysisResultState.ArgumentMismatch) Then ' Dev10 has squiggles under the operand of the AddressOf. The syntax of addressOfExpression ' is the complete AddressOf expression, so we need to get the operand first. Dim addressOfOperandSyntax = addressOfExpression.Syntax If addressOfOperandSyntax.Kind = SyntaxKind.AddressOfExpression Then addressOfOperandSyntax = DirectCast(addressOfOperandSyntax, UnaryExpressionSyntax).Operand End If If addressOfExpression.MethodGroup.ResultKind = LookupResultKind.Inaccessible Then ReportDiagnostic(diagnostics, addressOfOperandSyntax, addressOfExpression.Binder.GetInaccessibleErrorInfo( bestSymbols(0))) Else Debug.Assert(addressOfExpression.MethodGroup.ResultKind = LookupResultKind.Good) End If ReportDelegateBindingIncompatible( addressOfOperandSyntax, toMethod.ContainingType, DirectCast(bestSymbols(0), MethodSymbol), diagnostics) Else If bestCandidatesState = OverloadResolution.CandidateAnalysisResultState.HasUseSiteError OrElse bestCandidatesState = OverloadResolution.CandidateAnalysisResultState.HasUnsupportedMetadata OrElse bestCandidatesState = OverloadResolution.CandidateAnalysisResultState.Ambiguous Then couldTryZeroArgumentRelaxation = False End If Dim unused = resolutionBinder.ReportOverloadResolutionFailureAndProduceBoundNode( addressOfExpression.MethodGroup.Syntax, addressOfMethodGroup, bestCandidates, bestSymbols, commonReturnType, boundArguments, Nothing, diagnostics, delegateSymbol:=toMethod.ContainingType, callerInfoOpt:=Nothing) End If bestCandidates.Free() Return New KeyValuePair(Of MethodSymbol, MethodConversionKind)(Nothing, MethodConversionKind.Error_OverloadResolution) End Function Private Shared Function ValidateMethodForDelegateInvoke( addressOfExpression As BoundAddressOfOperator, analysisResult As OverloadResolution.CandidateAnalysisResult, toMethod As MethodSymbol, ignoreMethodReturnType As Boolean, useZeroArgumentRelaxation As Boolean, diagnostics As BindingDiagnosticBag ) As KeyValuePair(Of MethodSymbol, MethodConversionKind) Dim methodConversions As MethodConversionKind = MethodConversionKind.Identity ' Dev10 has squiggles under the operand of the AddressOf. The syntax of addressOfExpression ' is the complete AddressOf expression, so we need to get the operand first. Dim addressOfOperandSyntax = addressOfExpression.Syntax If addressOfOperandSyntax.Kind = SyntaxKind.AddressOfExpression Then addressOfOperandSyntax = DirectCast(addressOfOperandSyntax, UnaryExpressionSyntax).Operand End If ' determine conversions based on return type Dim useSiteInfo = addressOfExpression.Binder.GetNewCompoundUseSiteInfo(diagnostics) Dim targetMethodSymbol = DirectCast(analysisResult.Candidate.UnderlyingSymbol, MethodSymbol) If Not ignoreMethodReturnType Then methodConversions = methodConversions Or Conversions.ClassifyMethodConversionBasedOnReturn(targetMethodSymbol.ReturnType, targetMethodSymbol.ReturnsByRef, toMethod.ReturnType, toMethod.ReturnsByRef, useSiteInfo) If diagnostics.Add(addressOfOperandSyntax, useSiteInfo) Then ' Suppress additional diagnostics diagnostics = BindingDiagnosticBag.Discarded End If End If If useZeroArgumentRelaxation Then Debug.Assert(toMethod.ParameterCount > 0) ' special flag for ignoring all arguments (zero argument relaxation) If targetMethodSymbol.ParameterCount = 0 Then methodConversions = methodConversions Or MethodConversionKind.AllArgumentsIgnored Else ' We can get here if all method's parameters are Optional/ParamArray, however, ' according to the language spec, zero arguments relaxation is allowed only ' if target method has no parameters. Here is the quote: ' "method referenced by the method pointer, but it is not applicable due to ' the fact that it has no parameters and the delegate type does, then the method ' is considered applicable and the parameters are simply ignored." ' ' There is a bug in Dev10, sometimes it erroneously allows zero-argument relaxation against ' a method with optional parameters, if parameters of the delegate invoke can be passed to ' the method (i.e. without dropping them). See unit-test Bug12211 for an example. methodConversions = methodConversions Or MethodConversionKind.Error_IllegalToIgnoreAllArguments End If Else ' determine conversions based on arguments methodConversions = methodConversions Or GetDelegateMethodConversionBasedOnArguments(analysisResult, toMethod, useSiteInfo) If diagnostics.Add(addressOfOperandSyntax, useSiteInfo) Then ' Suppress additional diagnostics diagnostics = BindingDiagnosticBag.Discarded End If End If ' Stubs for ByRef returning methods are not supported. ' We could easily support a stub for the case when return value is dropped, ' but enabling other kinds of stubs later can lead to breaking changes ' because those relaxations could be "better". If Not ignoreMethodReturnType AndAlso targetMethodSymbol.ReturnsByRef AndAlso Conversions.IsDelegateRelaxationSupportedFor(methodConversions) AndAlso Conversions.IsStubRequiredForMethodConversion(methodConversions) Then methodConversions = methodConversions Or MethodConversionKind.Error_StubNotSupported End If If Conversions.IsDelegateRelaxationSupportedFor(methodConversions) Then diagnostics.AddRange(analysisResult.TypeArgumentInferenceDiagnosticsOpt) If addressOfExpression.MethodGroup.ResultKind = LookupResultKind.Good Then addressOfExpression.Binder.CheckMemberTypeAccessibility(diagnostics, addressOfOperandSyntax, targetMethodSymbol) Return New KeyValuePair(Of MethodSymbol, MethodConversionKind)(targetMethodSymbol, methodConversions) End If methodConversions = methodConversions Or MethodConversionKind.Error_Unspecified Else ReportDelegateBindingIncompatible( addressOfOperandSyntax, toMethod.ContainingType, targetMethodSymbol, diagnostics) End If Debug.Assert((methodConversions And MethodConversionKind.AllErrorReasons) <> 0) If addressOfExpression.MethodGroup.ResultKind = LookupResultKind.Inaccessible Then ReportDiagnostic(diagnostics, addressOfOperandSyntax, addressOfExpression.Binder.GetInaccessibleErrorInfo( analysisResult.Candidate.UnderlyingSymbol)) Else Debug.Assert(addressOfExpression.MethodGroup.ResultKind = LookupResultKind.Good) End If Return New KeyValuePair(Of MethodSymbol, MethodConversionKind)(Nothing, methodConversions) End Function Private Shared Sub ReportDelegateBindingMismatchStrictOff( syntax As SyntaxNode, delegateType As NamedTypeSymbol, targetMethodSymbol As MethodSymbol, diagnostics As BindingDiagnosticBag ) ' Option Strict On does not allow narrowing in implicit type conversion between method '{0}' and delegate "{1}". If targetMethodSymbol.ReducedFrom Is Nothing Then ReportDiagnostic(diagnostics, syntax, ERRID.ERR_DelegateBindingMismatchStrictOff2, targetMethodSymbol, CustomSymbolDisplayFormatter.DelegateSignature(delegateType)) Else ' This is an extension method. ReportDiagnostic(diagnostics, syntax, ERRID.ERR_DelegateBindingMismatchStrictOff3, targetMethodSymbol, CustomSymbolDisplayFormatter.DelegateSignature(delegateType), targetMethodSymbol.ContainingType) End If End Sub Private Shared Sub ReportDelegateBindingIncompatible( syntax As SyntaxNode, delegateType As NamedTypeSymbol, targetMethodSymbol As MethodSymbol, diagnostics As BindingDiagnosticBag ) ' Option Strict On does not allow narrowing in implicit type conversion between method '{0}' and delegate "{1}". If targetMethodSymbol.ReducedFrom Is Nothing Then ReportDiagnostic(diagnostics, syntax, ERRID.ERR_DelegateBindingIncompatible2, targetMethodSymbol, CustomSymbolDisplayFormatter.DelegateSignature(delegateType)) Else ' This is an extension method. ReportDiagnostic(diagnostics, syntax, ERRID.ERR_DelegateBindingIncompatible3, targetMethodSymbol, CustomSymbolDisplayFormatter.DelegateSignature(delegateType), targetMethodSymbol.ContainingType) End If End Sub ''' <summary> ''' Determines the method conversion for delegates based on the arguments. ''' </summary> ''' <param name="bestResult">The resolution result.</param> ''' <param name="delegateInvoke">The delegate invoke method.</param> Private Shared Function GetDelegateMethodConversionBasedOnArguments( bestResult As OverloadResolution.CandidateAnalysisResult, delegateInvoke As MethodSymbol, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) As MethodConversionKind Dim methodConversions As MethodConversionKind = MethodConversionKind.Identity ' in contrast to the native compiler we know that there is a legal conversion and we do not ' need to classify invalid conversions. ' however there is still the ParamArray expansion that needs special treatment. ' if there is one conversion needed, the array ConversionsOpt contains all conversions for all used parameters ' (including e.g. identity conversion). If a ParamArray was expanded, there will be a conversion for each ' expanded parameter. Dim bestCandidate As OverloadResolution.Candidate = bestResult.Candidate Dim candidateParameterCount = bestCandidate.ParameterCount Dim candidateLastParameterIndex = candidateParameterCount - 1 Dim delegateParameterCount = delegateInvoke.ParameterCount Dim lastCommonIndex = Math.Min(candidateParameterCount, delegateParameterCount) - 1 ' IsExpandedParamArrayForm is true if there was no, one or more parameters given for the ParamArray ' Note: if an array was passed, IsExpandedParamArrayForm is false. If bestResult.IsExpandedParamArrayForm Then ' Dev10 always sets the ExcessOptionalArgumentsOnTarget whenever the last parameter of the target was a ' ParamArray. This forces a stub for the ParamArray conversion, that is needed for the ParamArray in any case. methodConversions = methodConversions Or MethodConversionKind.ExcessOptionalArgumentsOnTarget ElseIf candidateParameterCount > delegateParameterCount Then ' An omission of optional parameters for expanded ParamArray form doesn't add anything new for ' the method conversion. Non-expanded ParamArray form, would be dismissed by overload resolution ' if there were omitted optional parameters because it is illegal to omit the ParamArray argument ' in non-expanded form. ' there are optional parameters that have not been exercised by the delegate. ' e.g. Delegate Sub(b As Byte) -> Sub Target(b As Byte, Optional c as Byte) methodConversions = methodConversions Or MethodConversionKind.ExcessOptionalArgumentsOnTarget #If DEBUG Then ' check that all unused parameters on the target are optional For parameterIndex = delegateParameterCount To candidateParameterCount - 1 Debug.Assert(bestCandidate.Parameters(parameterIndex).IsOptional) Next #End If ElseIf lastCommonIndex >= 0 AndAlso bestCandidate.Parameters(lastCommonIndex).IsParamArray AndAlso delegateInvoke.Parameters(lastCommonIndex).IsByRef AndAlso bestCandidate.Parameters(lastCommonIndex).IsByRef AndAlso Not bestResult.ConversionsOpt.IsDefaultOrEmpty AndAlso Not Conversions.IsIdentityConversion(bestResult.ConversionsOpt(lastCommonIndex).Key) Then ' Dev10 has the following behavior that needs to be re-implemented: ' Using ' Sub Target(ByRef Base()) ' with a ' Delegate Sub Del(ByRef ParamArray Base()) ' does not create a stub and the values are transported ByRef ' however using a ' Sub Target(ByRef ParamArray Base()) ' with a ' Delegate Del(ByRef Derived()) (with or without ParamArray, works with Option Strict Off only) ' creates a stub and transports the values ByVal. ' Note: if the ParamArray is not expanded, the parameter count must match Debug.Assert(candidateParameterCount = delegateParameterCount) Debug.Assert(Conversions.IsWideningConversion(bestResult.ConversionsOpt(lastCommonIndex).Key)) Dim conv = Conversions.ClassifyConversion(bestCandidate.Parameters(lastCommonIndex).Type, delegateInvoke.Parameters(lastCommonIndex).Type, useSiteInfo) methodConversions = methodConversions Or Conversions.ClassifyMethodConversionBasedOnArgumentConversion(conv.Key, delegateInvoke.Parameters(lastCommonIndex).Type) End If ' the overload resolution does not consider ByRef/ByVal mismatches, so we need to check the ' parameters here. ' first iterate over the common parameters For parameterIndex = 0 To lastCommonIndex If delegateInvoke.Parameters(parameterIndex).IsByRef <> bestCandidate.Parameters(parameterIndex).IsByRef Then methodConversions = methodConversions Or MethodConversionKind.Error_ByRefByValMismatch Exit For End If Next ' after the loop above the remaining parameters on the target can only be optional and/or a ParamArray If bestResult.IsExpandedParamArrayForm AndAlso (methodConversions And MethodConversionKind.Error_ByRefByValMismatch) <> MethodConversionKind.Error_ByRefByValMismatch Then ' if delegateParameterCount is smaller than targetParameterCount the for loop does not ' execute Dim lastTargetParameterIsByRef = bestCandidate.Parameters(candidateLastParameterIndex).IsByRef Debug.Assert(bestCandidate.Parameters(candidateLastParameterIndex).IsParamArray) For parameterIndex = lastCommonIndex + 1 To delegateParameterCount - 1 ' test against the last parameter of the target method If delegateInvoke.Parameters(parameterIndex).IsByRef <> lastTargetParameterIsByRef Then methodConversions = methodConversions Or MethodConversionKind.Error_ByRefByValMismatch Exit For End If Next End If ' there have been conversions, check them all If Not bestResult.ConversionsOpt.IsDefaultOrEmpty Then For conversionIndex = 0 To bestResult.ConversionsOpt.Length - 1 Dim conversion = bestResult.ConversionsOpt(conversionIndex) Dim delegateParameterType = delegateInvoke.Parameters(conversionIndex).Type methodConversions = methodConversions Or Conversions.ClassifyMethodConversionBasedOnArgumentConversion(conversion.Key, delegateParameterType) Next End If ' in case of ByRef, there might also be backward conversions If Not bestResult.ConversionsBackOpt.IsDefaultOrEmpty Then For conversionIndex = 0 To bestResult.ConversionsBackOpt.Length - 1 Dim conversion = bestResult.ConversionsBackOpt(conversionIndex) If Not Conversions.IsIdentityConversion(conversion.Key) Then Dim targetMethodParameterType = bestCandidate.Parameters(conversionIndex).Type methodConversions = methodConversions Or Conversions.ClassifyMethodConversionBasedOnArgumentConversion(conversion.Key, targetMethodParameterType) End If Next End If Return methodConversions End Function ''' <summary> ''' Classifies the address of conversion. ''' </summary> ''' <param name="source">The bound AddressOf expression.</param> ''' <param name="destination">The target type to convert this AddressOf expression to.</param><returns></returns> Friend Shared Function ClassifyAddressOfConversion( source As BoundAddressOfOperator, destination As TypeSymbol ) As ConversionKind Return source.GetConversionClassification(destination) End Function Private Shared ReadOnly s_checkDelegateParameterModifierCallback As CheckParameterModifierDelegate = AddressOf CheckDelegateParameterModifier ''' <summary> ''' Checks if a parameter is a ParamArray and reports this as an error. ''' </summary> ''' <param name="container">The containing type.</param> ''' <param name="token">The current parameter token.</param> ''' <param name="flag">The flags of this parameter.</param> ''' <param name="diagnostics">The diagnostics.</param> Private Shared Function CheckDelegateParameterModifier( container As Symbol, token As SyntaxToken, flag As SourceParameterFlags, diagnostics As BindingDiagnosticBag ) As SourceParameterFlags ' 9.2.5.4: ParamArray parameters may not be specified in delegate or event declarations. If (flag And SourceParameterFlags.ParamArray) = SourceParameterFlags.ParamArray Then Dim location = token.GetLocation() diagnostics.Add(ERRID.ERR_ParamArrayIllegal1, location, GetDelegateOrEventKeywordText(container)) flag = flag And (Not SourceParameterFlags.ParamArray) End If ' 9.2.5.3 Optional parameters may not be specified on delegate or event declarations If (flag And SourceParameterFlags.Optional) = SourceParameterFlags.Optional Then Dim location = token.GetLocation() diagnostics.Add(ERRID.ERR_OptionalIllegal1, location, GetDelegateOrEventKeywordText(container)) flag = flag And (Not SourceParameterFlags.Optional) End If Return flag End Function Private Shared Function GetDelegateOrEventKeywordText(sym As Symbol) As String Dim keyword As SyntaxKind If sym.Kind = SymbolKind.Event Then keyword = SyntaxKind.EventKeyword ElseIf TypeOf sym.ContainingType Is SynthesizedEventDelegateSymbol Then keyword = SyntaxKind.EventKeyword Else keyword = SyntaxKind.DelegateKeyword End If Return SyntaxFacts.GetText(keyword) End Function ''' <summary> ''' Reclassifies the bound address of operator into a delegate creation expression (if there is no delegate ''' relaxation required) or into a bound lambda expression (which gets a delegate creation expression later on) ''' </summary> ''' <param name="addressOfExpression">The AddressOf expression.</param> ''' <param name="delegateResolutionResult">The delegate resolution result.</param> ''' <param name="targetType">Type of the target.</param> ''' <param name="diagnostics">The diagnostics.</param><returns></returns> Friend Function ReclassifyAddressOf( addressOfExpression As BoundAddressOfOperator, ByRef delegateResolutionResult As DelegateResolutionResult, targetType As TypeSymbol, diagnostics As BindingDiagnosticBag, isForHandles As Boolean, warnIfResultOfAsyncMethodIsDroppedDueToRelaxation As Boolean ) As BoundExpression If addressOfExpression.HasErrors Then Return addressOfExpression End If Dim boundLambda As BoundLambda = Nothing Dim relaxationReceiverPlaceholder As BoundRValuePlaceholder = Nothing Dim syntaxNode = addressOfExpression.Syntax Dim targetMethod As MethodSymbol = delegateResolutionResult.Target Dim reducedFromDefinition As MethodSymbol = targetMethod.ReducedFrom Dim sourceMethodGroup = addressOfExpression.MethodGroup Dim receiver As BoundExpression = sourceMethodGroup.ReceiverOpt Dim resolvedTypeOrValueReceiver As BoundExpression = Nothing If receiver IsNot Nothing AndAlso Not addressOfExpression.HasErrors AndAlso Not delegateResolutionResult.Diagnostics.Diagnostics.HasAnyErrors Then receiver = AdjustReceiverTypeOrValue(receiver, receiver.Syntax, targetMethod.IsShared, diagnostics, resolvedTypeOrValueReceiver) End If If Me.OptionStrict = OptionStrict.On AndAlso Conversions.IsNarrowingConversion(delegateResolutionResult.DelegateConversions) Then Dim addressOfOperandSyntax = addressOfExpression.Syntax If addressOfOperandSyntax.Kind = SyntaxKind.AddressOfExpression Then addressOfOperandSyntax = DirectCast(addressOfOperandSyntax, UnaryExpressionSyntax).Operand End If ' Option Strict On does not allow narrowing in implicit type conversion between method '{0}' and delegate "{1}". ReportDelegateBindingMismatchStrictOff(addressOfOperandSyntax, DirectCast(targetType, NamedTypeSymbol), targetMethod, diagnostics) Else ' When the target method is an extension method, we are creating so called curried delegate. ' However, CLR doesn't support creating curried delegates that close over a ByRef 'this' argument. ' A similar problem exists when the 'this' argument is a value type. For these cases we need a stub too, ' but they are not covered by MethodConversionKind. If Conversions.IsStubRequiredForMethodConversion(delegateResolutionResult.MethodConversions) OrElse (reducedFromDefinition IsNot Nothing AndAlso (reducedFromDefinition.Parameters(0).IsByRef OrElse targetMethod.ReceiverType.IsTypeParameter() OrElse targetMethod.ReceiverType.IsValueType)) Then ' because of a delegate relaxation there is a conversion needed to create a delegate instance. ' We will create a lambda with the exact signature of the delegate. This lambda itself will ' call the target method. boundLambda = BuildDelegateRelaxationLambda(syntaxNode, sourceMethodGroup.Syntax, receiver, targetMethod, sourceMethodGroup.TypeArgumentsOpt, sourceMethodGroup.QualificationKind, DirectCast(targetType, NamedTypeSymbol).DelegateInvokeMethod, delegateResolutionResult.DelegateConversions And ConversionKind.DelegateRelaxationLevelMask, isZeroArgumentKnownToBeUsed:=(delegateResolutionResult.MethodConversions And MethodConversionKind.AllArgumentsIgnored) <> 0, diagnostics:=diagnostics, warnIfResultOfAsyncMethodIsDroppedDueToRelaxation:=warnIfResultOfAsyncMethodIsDroppedDueToRelaxation, relaxationReceiverPlaceholder:=relaxationReceiverPlaceholder) End If End If Dim target As MethodSymbol = delegateResolutionResult.Target ' Check if the target is a partial method without implementation provided If Not isForHandles AndAlso target.IsPartialWithoutImplementation Then ReportDiagnostic(diagnostics, addressOfExpression.MethodGroup.Syntax, ERRID.ERR_NoPartialMethodInAddressOf1, target) End If Dim newReceiver As BoundExpression If receiver IsNot Nothing Then If receiver.IsPropertyOrXmlPropertyAccess() Then receiver = MakeRValue(receiver, diagnostics) End If newReceiver = Nothing Else newReceiver = If(resolvedTypeOrValueReceiver, sourceMethodGroup.ReceiverOpt) End If sourceMethodGroup = sourceMethodGroup.Update(sourceMethodGroup.TypeArgumentsOpt, sourceMethodGroup.Methods, sourceMethodGroup.PendingExtensionMethodsOpt, sourceMethodGroup.ResultKind, newReceiver, sourceMethodGroup.QualificationKind) ' the delegate creation has the lambda stored internally to not clutter the bound tree with synthesized nodes ' in the first pass. Later on in the DelegateRewriter the node get's rewritten with the lambda if needed. Return New BoundDelegateCreationExpression(syntaxNode, receiver, target, boundLambda, relaxationReceiverPlaceholder, sourceMethodGroup, targetType, hasErrors:=False) End Function Private Function BuildDelegateRelaxationLambda( syntaxNode As SyntaxNode, methodGroupSyntax As SyntaxNode, receiver As BoundExpression, targetMethod As MethodSymbol, typeArgumentsOpt As BoundTypeArguments, qualificationKind As QualificationKind, delegateInvoke As MethodSymbol, delegateRelaxation As ConversionKind, isZeroArgumentKnownToBeUsed As Boolean, warnIfResultOfAsyncMethodIsDroppedDueToRelaxation As Boolean, diagnostics As BindingDiagnosticBag, <Out()> ByRef relaxationReceiverPlaceholder As BoundRValuePlaceholder ) As BoundLambda relaxationReceiverPlaceholder = Nothing Dim unconstructedTargetMethod As MethodSymbol = targetMethod.ConstructedFrom If typeArgumentsOpt Is Nothing AndAlso unconstructedTargetMethod.IsGenericMethod Then typeArgumentsOpt = New BoundTypeArguments(methodGroupSyntax, targetMethod.TypeArguments) typeArgumentsOpt.SetWasCompilerGenerated() End If Dim actualReceiver As BoundExpression = receiver ' Figure out if we need to capture the receiver in a temp before creating the lambda ' in order to enforce correct semantics. If actualReceiver IsNot Nothing AndAlso actualReceiver.IsValue() AndAlso Not actualReceiver.HasErrors Then If actualReceiver.IsInstanceReference() AndAlso targetMethod.ReceiverType.IsReferenceType Then Debug.Assert(Not actualReceiver.Type.IsTypeParameter()) Debug.Assert(Not actualReceiver.IsLValue) ' See the comment below why this is important. Else ' Will need to capture the receiver in a temp, rewriter do the job. relaxationReceiverPlaceholder = New BoundRValuePlaceholder(actualReceiver.Syntax, actualReceiver.Type) actualReceiver = relaxationReceiverPlaceholder End If End If Dim methodGroup = New BoundMethodGroup(methodGroupSyntax, typeArgumentsOpt, ImmutableArray.Create(unconstructedTargetMethod), LookupResultKind.Good, actualReceiver, qualificationKind) methodGroup.SetWasCompilerGenerated() Return BuildDelegateRelaxationLambda(syntaxNode, delegateInvoke, methodGroup, delegateRelaxation, isZeroArgumentKnownToBeUsed, warnIfResultOfAsyncMethodIsDroppedDueToRelaxation, diagnostics) End Function ''' <summary> ''' Build a lambda that has a shape of the [delegateInvoke] and calls ''' the only method from the [methodGroup] passing all parameters of the lambda ''' as arguments for the call. ''' Note, that usually the receiver of the [methodGroup] should be captured before entering the ''' relaxation lambda in order to prevent its reevaluation every time the lambda is invoked and ''' prevent its mutation. ''' ''' !!! Therefore, it is not common to call this overload directly. !!! ''' ''' </summary> ''' <param name="syntaxNode">Location to use for various synthetic nodes and symbols.</param> ''' <param name="delegateInvoke">The Invoke method to "implement".</param> ''' <param name="methodGroup">The method group with the only method in it.</param> ''' <param name="delegateRelaxation">Delegate relaxation to store within the new BoundLambda node.</param> ''' <param name="diagnostics"></param> Private Function BuildDelegateRelaxationLambda( syntaxNode As SyntaxNode, delegateInvoke As MethodSymbol, methodGroup As BoundMethodGroup, delegateRelaxation As ConversionKind, isZeroArgumentKnownToBeUsed As Boolean, warnIfResultOfAsyncMethodIsDroppedDueToRelaxation As Boolean, diagnostics As BindingDiagnosticBag ) As BoundLambda Debug.Assert(delegateInvoke.MethodKind = MethodKind.DelegateInvoke) Debug.Assert(methodGroup.Methods.Length = 1) Debug.Assert(methodGroup.PendingExtensionMethodsOpt Is Nothing) Debug.Assert((delegateRelaxation And (Not ConversionKind.DelegateRelaxationLevelMask)) = 0) ' build lambda symbol parameters matching the invocation method exactly. To do this, ' we'll create a BoundLambdaParameterSymbol for each parameter of the invoke method. Dim delegateInvokeReturnType = delegateInvoke.ReturnType Dim invokeParameters = delegateInvoke.Parameters Dim invokeParameterCount = invokeParameters.Length Dim lambdaSymbolParameters(invokeParameterCount - 1) As BoundLambdaParameterSymbol Dim addressOfLocation As Location = syntaxNode.GetLocation() For parameterIndex = 0 To invokeParameterCount - 1 Dim parameter = invokeParameters(parameterIndex) lambdaSymbolParameters(parameterIndex) = New BoundLambdaParameterSymbol(GeneratedNames.MakeDelegateRelaxationParameterName(parameterIndex), parameter.Ordinal, parameter.Type, parameter.IsByRef, syntaxNode, addressOfLocation) Next ' even if the return value is dropped, we're using the delegate's return type for ' this lambda symbol. Dim lambdaSymbol = New SynthesizedLambdaSymbol(SynthesizedLambdaKind.DelegateRelaxationStub, syntaxNode, lambdaSymbolParameters.AsImmutable(), delegateInvokeReturnType, Me) ' the body of the lambda only contains a call to the target (or a return of the return value of ' the call in case of a function) ' for each parameter of the lambda symbol/invoke method we will create a bound parameter, except ' we are implementing a zero argument relaxation. ' These parameters will be used in the method invocation as passed parameters. Dim method As MethodSymbol = methodGroup.Methods(0) Dim droppedArguments = isZeroArgumentKnownToBeUsed OrElse (invokeParameterCount > 0 AndAlso method.ParameterCount = 0) Dim targetParameterCount = If(droppedArguments, 0, invokeParameterCount) Dim lambdaBoundParameters(targetParameterCount - 1) As BoundExpression If Not droppedArguments Then For parameterIndex = 0 To lambdaSymbolParameters.Length - 1 Dim lambdaSymbolParameter = lambdaSymbolParameters(parameterIndex) Dim boundParameter = New BoundParameter(syntaxNode, lambdaSymbolParameter, lambdaSymbolParameter.Type) boundParameter.SetWasCompilerGenerated() lambdaBoundParameters(parameterIndex) = boundParameter Next End If 'The invocation of the target method must be bound in the context of the lambda 'The reason is that binding the invoke may introduce local symbols and they need 'to be properly parented to the lambda and not to the outer method. Dim lambdaBinder = New LambdaBodyBinder(lambdaSymbol, Me) ' Dev10 ignores the type characters used in the operand of an AddressOf operator. ' NOTE: we suppress suppressAbstractCallDiagnostics because it ' should have been reported already Dim boundInvocationExpression As BoundExpression = lambdaBinder.BindInvocationExpression(syntaxNode, syntaxNode, TypeCharacter.None, methodGroup, lambdaBoundParameters.AsImmutable(), Nothing, diagnostics, suppressAbstractCallDiagnostics:=True, callerInfoOpt:=Nothing) boundInvocationExpression.SetWasCompilerGenerated() ' In case of a function target that got assigned to a sub delegate, the return value will be dropped Dim statementList As ImmutableArray(Of BoundStatement) = Nothing If lambdaSymbol.IsSub Then Dim statements(1) As BoundStatement Dim boundStatement As BoundStatement = New BoundExpressionStatement(syntaxNode, boundInvocationExpression) boundStatement.SetWasCompilerGenerated() statements(0) = boundStatement boundStatement = New BoundReturnStatement(syntaxNode, Nothing, Nothing, Nothing) boundStatement.SetWasCompilerGenerated() statements(1) = boundStatement statementList = statements.AsImmutableOrNull If warnIfResultOfAsyncMethodIsDroppedDueToRelaxation AndAlso Not method.IsSub Then If Not method.IsAsync Then warnIfResultOfAsyncMethodIsDroppedDueToRelaxation = False If method.MethodKind = MethodKind.DelegateInvoke AndAlso methodGroup.ReceiverOpt IsNot Nothing AndAlso methodGroup.ReceiverOpt.Kind = BoundKind.Conversion Then Dim receiver = DirectCast(methodGroup.ReceiverOpt, BoundConversion) If Not receiver.ExplicitCastInCode AndAlso receiver.Operand.Kind = BoundKind.Lambda AndAlso DirectCast(receiver.Operand, BoundLambda).LambdaSymbol.IsAsync AndAlso receiver.Type.IsDelegateType() AndAlso receiver.Type.IsAnonymousType Then warnIfResultOfAsyncMethodIsDroppedDueToRelaxation = True End If End If Else warnIfResultOfAsyncMethodIsDroppedDueToRelaxation = method.ContainingAssembly Is Compilation.Assembly End If If warnIfResultOfAsyncMethodIsDroppedDueToRelaxation Then ReportDiagnostic(diagnostics, syntaxNode, ERRID.WRN_UnobservedAwaitableDelegate) End If End If Else ' process conversions between the return types of the target and invoke function if needed. boundInvocationExpression = lambdaBinder.ApplyImplicitConversion(syntaxNode, delegateInvokeReturnType, boundInvocationExpression, diagnostics) Dim returnstmt As BoundStatement = New BoundReturnStatement(syntaxNode, boundInvocationExpression, Nothing, Nothing) returnstmt.SetWasCompilerGenerated() statementList = ImmutableArray.Create(returnstmt) End If Dim lambdaBody = New BoundBlock(syntaxNode, Nothing, ImmutableArray(Of LocalSymbol).Empty, statementList) lambdaBody.SetWasCompilerGenerated() Dim boundLambda = New BoundLambda(syntaxNode, lambdaSymbol, lambdaBody, ReadOnlyBindingDiagnostic(Of AssemblySymbol).Empty, Nothing, delegateRelaxation, MethodConversionKind.Identity) boundLambda.SetWasCompilerGenerated() Return boundLambda End Function End Class End Namespace