/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Binding/Binder_Invocation.vb
3 313 строк
177 KB
Tomáš Matoušek
Clean up KeyValuePair polyfills (#78872)
24 июн 2025, 03:17
Не верифицирован
24 июн 2025, 03:17
f294360
Код
Авторство
О чём код?
' 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.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic ' Binding of method/property invocation is implemented in this part. Partial Friend Class Binder Private Function CreateBoundMethodGroup( node As SyntaxNode, lookupResult As LookupResult, lookupOptionsUsed As LookupOptions, withDependencies As Boolean, receiver As BoundExpression, typeArgumentsOpt As BoundTypeArguments, qualKind As QualificationKind, Optional hasError As Boolean = False ) As BoundMethodGroup Dim pendingExtensionMethods As ExtensionMethodGroup = Nothing Debug.Assert(lookupResult.Kind = LookupResultKind.Good OrElse lookupResult.Kind = LookupResultKind.Inaccessible) ' Name lookup does not look for extension methods if it found a suitable ' instance method. So, if the first symbol we have is not a reduced extension ' method, we might need to look for extension methods later, on demand. Debug.Assert((lookupOptionsUsed And LookupOptions.EagerlyLookupExtensionMethods) = 0) If lookupResult.IsGood AndAlso Not lookupResult.Symbols(0).IsReducedExtensionMethod() Then pendingExtensionMethods = New ExtensionMethodGroup(Me, lookupOptionsUsed, withDependencies) End If Return New BoundMethodGroup( node, typeArgumentsOpt, lookupResult.Symbols.ToDowncastedImmutable(Of MethodSymbol), pendingExtensionMethods, lookupResult.Kind, receiver, qualKind, hasErrors:=hasError) End Function ''' <summary> ''' Returns if all the rules for a "Me.New" or "MyBase.New" constructor call are satisfied: ''' a) In instance constructor body ''' b) First statement of that constructor ''' c) "Me", "MyClass", or "MyBase" is the receiver. ''' </summary> Private Function IsConstructorCallAllowed(invocationExpression As InvocationExpressionSyntax, boundMemberGroup As BoundMethodOrPropertyGroup) As Boolean If Me.ContainingMember.Kind = SymbolKind.Method AndAlso DirectCast(Me.ContainingMember, MethodSymbol).MethodKind = MethodKind.Constructor Then ' (a) we are in an instance constructor body Dim node As VisualBasicSyntaxNode = invocationExpression.Parent If node Is Nothing OrElse (node.Kind <> SyntaxKind.CallStatement AndAlso node.Kind <> SyntaxKind.ExpressionStatement) Then Return False End If Dim nodeParent As VisualBasicSyntaxNode = node.Parent If nodeParent Is Nothing OrElse nodeParent.Kind <> SyntaxKind.ConstructorBlock Then Return False End If If DirectCast(nodeParent, ConstructorBlockSyntax).Statements(0) Is node Then ' (b) call statement we are binding is 'the first' statement of the constructor Dim receiver As BoundExpression = boundMemberGroup.ReceiverOpt If receiver IsNot Nothing AndAlso (receiver.Kind = BoundKind.MeReference OrElse receiver.Kind = BoundKind.MyBaseReference OrElse receiver.Kind = BoundKind.MyClassReference) Then ' (c) receiver is 'Me'/'MyClass'/'MyBase' Return True End If End If End If Return False End Function Friend Class ConstructorCallArgumentsBinder Inherits Binder Public Sub New(containingBinder As Binder) MyBase.New(containingBinder) End Sub Protected Overrides ReadOnly Property IsInsideChainedConstructorCallArguments As Boolean Get Return True End Get End Property End Class ''' <summary> ''' Bind a Me.New(...), MyBase.New (...), MyClass.New(...) constructor call. ''' (NOT a normal constructor call like New Type(...)). ''' </summary> Private Function BindDirectConstructorCall(node As InvocationExpressionSyntax, group As BoundMethodGroup, diagnostics As BindingDiagnosticBag) As BoundExpression Dim boundArguments As ImmutableArray(Of BoundExpression) = Nothing Dim argumentNames As ImmutableArray(Of String) = Nothing Dim argumentNamesLocations As ImmutableArray(Of Location) = Nothing Dim argumentList As ArgumentListSyntax = node.ArgumentList Debug.Assert(IsGroupOfConstructors(group)) ' Direct constructor call is only allowed if: (a) we are in an instance constructor body, ' and (b) call statement we are binding is 'the first' statement of the constructor, ' and (c) receiver is 'Me'/'MyClass'/'MyBase' If IsConstructorCallAllowed(node, group) Then ' Bind arguments with special binder that prevents use of Me. Dim argumentsBinder As Binder = New ConstructorCallArgumentsBinder(Me) argumentsBinder.BindArgumentsAndNames(argumentList, boundArguments, argumentNames, argumentNamesLocations, diagnostics) ' Bind constructor call, errors will be generated if needed Return BindInvocationExpression(node, node.Expression, ExtractTypeCharacter(node.Expression), group, boundArguments, argumentNames, diagnostics, allowConstructorCall:=True, callerInfoOpt:=group.Syntax) Else ' Error case -- constructor call in wrong location. ' Report error BC30282 about invalid constructor call ' For semantic model / IDE purposes, we still bind it even if in a location that wasn't allowed. If Not group.HasErrors Then ReportDiagnostic(diagnostics, group.Syntax, ERRID.ERR_InvalidConstructorCall) End If BindArgumentsAndNames(argumentList, boundArguments, argumentNames, argumentNamesLocations, diagnostics) ' Bind constructor call, ignore errors by putting into discarded bag. Dim expr = BindInvocationExpression(node, node.Expression, ExtractTypeCharacter(node.Expression), group, boundArguments, argumentNames, BindingDiagnosticBag.Discarded, allowConstructorCall:=True, callerInfoOpt:=group.Syntax) If expr.Kind = BoundKind.Call Then ' Set HasErrors to prevent cascading errors. Dim callExpr = DirectCast(expr, BoundCall) expr = New BoundCall( callExpr.Syntax, callExpr.Method, callExpr.MethodGroupOpt, callExpr.ReceiverOpt, callExpr.Arguments, callExpr.DefaultArguments, callExpr.ConstantValueOpt, isLValue:=False, suppressObjectClone:=False, type:=callExpr.Type, hasErrors:=True) End If Return expr End If End Function Private Function BindInvocationExpression(node As InvocationExpressionSyntax, diagnostics As BindingDiagnosticBag) As BoundExpression ' Set "IsInvocationsOrAddressOf" to prevent binding to return value variable. Dim target As BoundExpression If node.Expression Is Nothing Then ' Must be conditional case Dim conditionalAccess As ConditionalAccessExpressionSyntax = node.GetCorrespondingConditionalAccessExpression() If conditionalAccess IsNot Nothing Then target = GetConditionalAccessReceiver(conditionalAccess) Else target = ReportDiagnosticAndProduceBadExpression(diagnostics, node, ERRID.ERR_Syntax).MakeCompilerGenerated() End If Else target = BindExpression(node.Expression, diagnostics:=diagnostics, isInvocationOrAddressOf:=True, isOperandOfConditionalBranch:=False, eventContext:=False) End If ' If 'target' is a bound constructor group, we need to do special checks and special processing of arguments. If target.Kind = BoundKind.MethodGroup Then Dim group = DirectCast(target, BoundMethodGroup) If IsGroupOfConstructors(group) Then Return BindDirectConstructorCall(node, group, diagnostics) End If End If Dim boundArguments As ImmutableArray(Of BoundExpression) = Nothing Dim argumentNames As ImmutableArray(Of String) = Nothing Dim argumentNamesLocations As ImmutableArray(Of Location) = Nothing Me.BindArgumentsAndNames(node.ArgumentList, boundArguments, argumentNames, argumentNamesLocations, diagnostics) If target.Kind = BoundKind.MethodGroup OrElse target.Kind = BoundKind.PropertyGroup Then Return BindInvocationExpressionPossiblyWithoutArguments( node, ExtractTypeCharacter(node.Expression), DirectCast(target, BoundMethodOrPropertyGroup), boundArguments, argumentNames, argumentNamesLocations, allowBindingWithoutArguments:=True, diagnostics:=diagnostics) End If If target.Kind = BoundKind.NamespaceExpression Then Dim namespaceExp As BoundNamespaceExpression = DirectCast(target, BoundNamespaceExpression) Dim diagInfo = ErrorFactory.ErrorInfo(ERRID.ERR_NamespaceNotExpression1, namespaceExp.NamespaceSymbol) ReportDiagnostic(diagnostics, node.Expression, diagInfo) ElseIf target.Kind = BoundKind.TypeExpression Then Dim typeExp As BoundTypeExpression = DirectCast(target, BoundTypeExpression) If Not IsCallStatementContext(node) Then ' Try default instance property through DefaultInstanceAlias Dim instance As BoundExpression = TryDefaultInstanceProperty(typeExp, diagnostics) If instance IsNot Nothing Then Return BindIndexedInvocationExpression( node, instance, boundArguments, argumentNames, argumentNamesLocations, allowBindingWithoutArguments:=False, hasIndexableTarget:=False, diagnostics:=diagnostics) End If End If Dim diagInfo = ErrorFactory.ErrorInfo(GetTypeNotExpressionErrorId(typeExp.Type), typeExp.Type) ReportDiagnostic(diagnostics, node.Expression, diagInfo) Else Return BindIndexedInvocationExpression( node, target, boundArguments, argumentNames, argumentNamesLocations, allowBindingWithoutArguments:=True, hasIndexableTarget:=False, diagnostics:=diagnostics) End If Return GenerateBadExpression(node, target, boundArguments) End Function ''' <summary> ''' Bind an invocation expression representing an array access, ''' delegate invocation, or default member. ''' </summary> Private Function BindIndexedInvocationExpression( node As InvocationExpressionSyntax, target As BoundExpression, boundArguments As ImmutableArray(Of BoundExpression), argumentNames As ImmutableArray(Of String), argumentNamesLocations As ImmutableArray(Of Location), allowBindingWithoutArguments As Boolean, <Out()> ByRef hasIndexableTarget As Boolean, diagnostics As BindingDiagnosticBag) As BoundExpression Debug.Assert(target.Kind <> BoundKind.NamespaceExpression) Debug.Assert(target.Kind <> BoundKind.TypeExpression) Debug.Assert(target.Kind <> BoundKind.MethodGroup) Debug.Assert(target.Kind <> BoundKind.PropertyGroup) hasIndexableTarget = False If Not target.IsLValue AndAlso target.Kind <> BoundKind.LateMemberAccess Then target = MakeRValue(target, diagnostics) End If Dim targetType As TypeSymbol = target.Type ' there are values or variables like "Nothing" which have no type If targetType IsNot Nothing Then ' this method is also called for e.g. Arrays because they are also InvocationExpressions ' if target is an array, then call BindArrayAccess only if target is not a direct successor ' of a call statement If targetType.IsArrayType Then hasIndexableTarget = True ' only bind to an array if this method was called outside of a call statement context If Not IsCallStatementContext(node) Then Return BindArrayAccess(node, target, boundArguments, argumentNames, diagnostics) End If ElseIf targetType.Kind = SymbolKind.NamedType AndAlso targetType.TypeKind = TypeKind.Delegate Then hasIndexableTarget = True ' an invocation of a delegate actually calls the delegate's Invoke method. Dim delegateInvoke = DirectCast(targetType, NamedTypeSymbol).DelegateInvokeMethod If delegateInvoke Is Nothing Then If Not target.HasErrors Then ReportDiagnostic(diagnostics, target.Syntax, ERRID.ERR_DelegateNoInvoke1, target.Type) End If ElseIf ReportDelegateInvokeUseSite(diagnostics, target.Syntax, targetType, delegateInvoke) Then delegateInvoke = Nothing End If If delegateInvoke IsNot Nothing Then Dim methodGroup = New BoundMethodGroup( If(node.Expression, node), Nothing, ImmutableArray.Create(Of MethodSymbol)(delegateInvoke), LookupResultKind.Good, target, QualificationKind.QualifiedViaValue).MakeCompilerGenerated() Return BindInvocationExpression( node, If(node.Expression, node), ExtractTypeCharacter(node.Expression), methodGroup, boundArguments, argumentNames, diagnostics, callerInfoOpt:=node, representCandidateInDiagnosticsOpt:=targetType) Else Dim badExpressionChildren = ArrayBuilder(Of BoundExpression).GetInstance() badExpressionChildren.Add(target) badExpressionChildren.AddRange(boundArguments) Return BadExpression(node, badExpressionChildren.ToImmutableAndFree(), ErrorTypeSymbol.UnknownResultType) End If End If End If If target.Kind = BoundKind.BadExpression Then ' Error already reported for a bad expression, so don't report another error ElseIf Not IsCallStatementContext(node) Then ' If the invocation is outside of a call statement ' context, bind to the default property group if any. If target.Type.SpecialType = SpecialType.System_Object OrElse target.Type.SpecialType = SpecialType.System_Array Then hasIndexableTarget = True Return BindLateBoundInvocation(node, Nothing, target, boundArguments, argumentNames, diagnostics, suppressLateBindingResolutionDiagnostics:=(target.Kind = BoundKind.LateMemberAccess)) End If If Not target.HasErrors Then ' Bind to the default property group. Dim defaultPropertyGroup As BoundExpression = BindDefaultPropertyGroup(If(node.Expression, node), target, diagnostics) If defaultPropertyGroup IsNot Nothing Then Debug.Assert(defaultPropertyGroup.Kind = BoundKind.PropertyGroup OrElse defaultPropertyGroup.Kind = BoundKind.MethodGroup OrElse defaultPropertyGroup.HasErrors) hasIndexableTarget = True If defaultPropertyGroup.Kind = BoundKind.PropertyGroup OrElse defaultPropertyGroup.Kind = BoundKind.MethodGroup Then Return BindInvocationExpressionPossiblyWithoutArguments( node, TypeCharacter.None, DirectCast(defaultPropertyGroup, BoundMethodOrPropertyGroup), boundArguments, argumentNames, argumentNamesLocations, allowBindingWithoutArguments, diagnostics) End If Else ReportNoDefaultProperty(target, diagnostics) End If End If ElseIf target.Kind = BoundKind.LateMemberAccess Then hasIndexableTarget = True Dim lateMember = DirectCast(target, BoundLateMemberAccess) Return BindLateBoundInvocation(node, Nothing, lateMember, boundArguments, argumentNames, diagnostics) ElseIf Not target.HasErrors Then ' "Expression is not a method." Dim diagInfo = ErrorFactory.ErrorInfo(ERRID.ERR_ExpectedProcedure) ReportDiagnostic(diagnostics, If(node.Expression, node), diagInfo) End If Return GenerateBadExpression(node, target, boundArguments) End Function Private Function BindInvocationExpressionPossiblyWithoutArguments( node As InvocationExpressionSyntax, typeChar As TypeCharacter, group As BoundMethodOrPropertyGroup, boundArguments As ImmutableArray(Of BoundExpression), argumentNames As ImmutableArray(Of String), argumentNamesLocations As ImmutableArray(Of Location), allowBindingWithoutArguments As Boolean, diagnostics As BindingDiagnosticBag) As BoundExpression ' Spec §11.8 Invocation Expressions ' ... ' If the method group only contains one accessible method, including both instance and ' extension methods, and that method takes no arguments and is a function, then the method ' group is interpreted as an invocation expression with an empty argument list and the result ' is used as the target of an invocation expression with the provided argument list(s). If allowBindingWithoutArguments AndAlso boundArguments.Length > 0 AndAlso Not IsCallStatementContext(node) AndAlso ShouldBindWithoutArguments(node, group, diagnostics) Then Dim tmpDiagnostics = BindingDiagnosticBag.GetInstance(diagnostics) Dim result As BoundExpression = Nothing Debug.Assert(node.Expression IsNot Nothing) ' NOTE: when binding without arguments, we pass node.Expression as the first parameter ' so that the new bound node references it instead of invocation expression Dim withoutArgs = BindInvocationExpression( node.Expression, node.Expression, typeChar, group, ImmutableArray(Of BoundExpression).Empty, Nothing, tmpDiagnostics, callerInfoOpt:=group.Syntax) If withoutArgs.Kind = BoundKind.Call OrElse withoutArgs.Kind = BoundKind.PropertyAccess Then ' We were able to bind the method group or property access without arguments, ' possibly with some diagnostic. diagnostics.AddRange(tmpDiagnostics) tmpDiagnostics.Clear() If withoutArgs.Kind = BoundKind.PropertyAccess Then Dim receiverOpt As BoundExpression = DirectCast(withoutArgs, BoundPropertyAccess).ReceiverOpt If receiverOpt?.Syntax Is withoutArgs.Syntax AndAlso Not receiverOpt.WasCompilerGenerated Then withoutArgs.MakeCompilerGenerated() End If withoutArgs = MakeRValue(withoutArgs, diagnostics) Else Dim receiverOpt As BoundExpression = DirectCast(withoutArgs, BoundCall).ReceiverOpt If receiverOpt?.Syntax Is withoutArgs.Syntax AndAlso Not receiverOpt.WasCompilerGenerated Then withoutArgs.MakeCompilerGenerated() End If End If If withoutArgs.Kind = BoundKind.BadExpression Then result = GenerateBadExpression(node, withoutArgs, boundArguments) Else Dim hasIndexableTarget = False ' Bind the invocation with arguments as an indexed invocation. Dim withArgs = BindIndexedInvocationExpression( node, withoutArgs, boundArguments, argumentNames, argumentNamesLocations, allowBindingWithoutArguments:=False, hasIndexableTarget:=hasIndexableTarget, diagnostics:=tmpDiagnostics) If hasIndexableTarget Then diagnostics.AddRange(tmpDiagnostics) result = withArgs Else ' Report BC32016 if something wrong. ReportDiagnostic(diagnostics, node.Expression, ERRID.ERR_FunctionResultCannotBeIndexed1, withoutArgs.ExpressionSymbol) ' If result of binding with no args was not indexable after all, then instead ' of just producing a bad expression, bind the invocation expression normally, ' but without reporting any more diagnostics. This produces more accurate ' bound nodes for semantic model questions and may allow the type of the ' expression to be computed, thus leading to fewer errors later. result = BindInvocationExpression( node, node.Expression, typeChar, group, boundArguments, argumentNames, BindingDiagnosticBag.Discarded, callerInfoOpt:=group.Syntax) End If End If End If tmpDiagnostics.Free() If result IsNot Nothing Then Return result End If End If Return BindInvocationExpression( node, If(node.Expression, group.Syntax), typeChar, group, boundArguments, argumentNames, diagnostics, callerInfoOpt:=group.Syntax) End Function ''' <summary> ''' Returns a BoundPropertyGroup if the expression represents a valid ''' default property access. If there is a default property but the property ''' access is invalid, a BoundBadExpression is returned. If there is no ''' default property for the expression type, Nothing is returned. ''' ''' Note, that default Query Indexer may be a method, not a property. ''' </summary> Private Function BindDefaultPropertyGroup(node As VisualBasicSyntaxNode, target As BoundExpression, diagnostics As BindingDiagnosticBag) As BoundExpression Dim result = LookupResult.GetInstance() Dim defaultMemberGroup As BoundExpression = Nothing Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics) MemberLookup.LookupDefaultProperty(result, target.Type, Me, useSiteInfo) ' We're not reporting any diagnostic if there are no symbols. Debug.Assert(result.HasSymbol OrElse Not result.HasDiagnostic) If result.HasSymbol Then defaultMemberGroup = BindSymbolAccess(node, result, LookupOptions.Default, target, Nothing, QualificationKind.QualifiedViaValue, diagnostics) Debug.Assert(defaultMemberGroup IsNot Nothing) Debug.Assert((defaultMemberGroup.Kind = BoundKind.BadExpression) OrElse (defaultMemberGroup.Kind = BoundKind.PropertyGroup)) Else ' All queryable sources have default indexer, which maps to an ElementAtOrDefault method or property on the source. Dim tempDiagnostics = BindingDiagnosticBag.GetInstance(diagnostics) target = MakeRValue(target, tempDiagnostics) Dim controlVariableType As TypeSymbol = Nothing target = ConvertToQueryableType(target, tempDiagnostics, controlVariableType) If controlVariableType IsNot Nothing Then result.Clear() Const options As LookupOptions = LookupOptions.AllMethodsOfAnyArity ' overload resolution filters methods by arity. LookupMember(result, target.Type, StringConstants.ElementAtMethod, 0, options, useSiteInfo) If result.IsGood Then Dim kind As SymbolKind = result.Symbols(0).Kind If kind = SymbolKind.Method OrElse kind = SymbolKind.Property Then diagnostics.AddRange(tempDiagnostics) defaultMemberGroup = BindSymbolAccess(node, result, options, target, Nothing, QualificationKind.QualifiedViaValue, diagnostics) End If End If End If tempDiagnostics.Free() End If diagnostics.Add(node, useSiteInfo) result.Free() ' We don't want the default property GROUP to override the meaning of the item it's being ' accessed off of, so mark it as compiler generated. If defaultMemberGroup IsNot Nothing Then defaultMemberGroup.SetWasCompilerGenerated() End If Return defaultMemberGroup End Function ''' <summary> ''' Tests whether or not the method or property group should be bound without arguments. ''' In case of method group it may also update the group by filtering out all subs ''' </summary> Private Function ShouldBindWithoutArguments(node As VisualBasicSyntaxNode, ByRef group As BoundMethodOrPropertyGroup, diagnostics As BindingDiagnosticBag) As Boolean Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics) Dim result = ShouldBindWithoutArguments(group, useSiteInfo) diagnostics.Add(node, useSiteInfo) Return result End Function Private Function ShouldBindWithoutArguments(ByRef group As BoundMethodOrPropertyGroup, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)) As Boolean If group.Kind = BoundKind.MethodGroup Then Dim newMethods As ArrayBuilder(Of MethodSymbol) = ArrayBuilder(Of MethodSymbol).GetInstance() ' check method group members Dim methodGroup = DirectCast(group, BoundMethodGroup) Debug.Assert(methodGroup.Methods.Length > 0) ' any sub should be removed from a group in case we try binding without arguments Dim shouldUpdateGroup As Boolean = False Dim atLeastOneFunction As Boolean = False ' Dev10 behavior: ' For instance methods - ' Check if all functions from the group (ignoring subs) ' have the same arity as specified in the call and 0 parameters. ' However, the part that handles arity check is rather inconsistent between methods ' overloaded within the same type and in derived type. Also, language spec doesn't mention ' any restrictions for arity. So, we will not try to duplicate Dev10 logic around arity ' because the logic is close to impossible to match and behavior change will not be a breaking ' change. ' In presence of extension methods the rules are more constrained- ' If group contains an extension method, it must be the only method in the group, ' it must have no parameters, must have no type parameters and must be a Function. ' Note, we should avoid requesting AdditionalExtensionMethods whenever possible because ' lookup of extension methods might be very expensive. Dim extensionMethod As MethodSymbol = Nothing For Each method In methodGroup.Methods If method.IsReducedExtensionMethod Then extensionMethod = method Exit For End If If (method.IsSub) Then If method.CanBeCalledWithNoParameters() Then ' If its a sub that could be called parameterlessly, it might hide the function. So it is included ' in the group for further processing in overload resolution (which will process possible hiding). ' If overload resolution does select the Sub, we'll get an error about return type not indexable. ' See Roslyn bug 14019 for example. newMethods.Add(method) Else ' ignore other subs entirely shouldUpdateGroup = True End If ElseIf method.ParameterCount > 0 Then ' any function with more than 0 parameters newMethods.Free() Return False Else newMethods.Add(method) atLeastOneFunction = True End If Next If extensionMethod Is Nothing Then Dim additionalExtensionMethods As ImmutableArray(Of MethodSymbol) = methodGroup.AdditionalExtensionMethods(useSiteInfo) If additionalExtensionMethods.Length > 0 Then Debug.Assert(methodGroup.Methods.Length > 0) ' We have at least one extension method in the group and it is not the only one method in the ' group. Cannot apply default property transformation. newMethods.Free() Return False End If Else newMethods.Free() Debug.Assert(extensionMethod IsNot Nothing) ' This method must have no parameters, must have no type parameters and must not be a Sub. Return methodGroup.Methods.Length = 1 AndAlso methodGroup.TypeArgumentsOpt Is Nothing AndAlso extensionMethod.ParameterCount = 0 AndAlso extensionMethod.Arity = 0 AndAlso Not extensionMethod.IsSub AndAlso methodGroup.AdditionalExtensionMethods(useSiteInfo).Length = 0 End If If Not atLeastOneFunction Then newMethods.Free() Return False End If If shouldUpdateGroup Then ' at least one sub was removed If newMethods.IsEmpty Then ' no functions left newMethods.Free() Return False End If ' there are some functions, update the group group = methodGroup.Update(methodGroup.TypeArgumentsOpt, newMethods.ToImmutable(), Nothing, methodGroup.ResultKind, methodGroup.ReceiverOpt, methodGroup.QualificationKind) End If newMethods.Free() Return True Else ' check property group members Dim propertyGroup = DirectCast(group, BoundPropertyGroup) Debug.Assert(propertyGroup.Properties.Length > 0) For Each prop In propertyGroup.Properties If (prop.ParameterCount > 0) Then Return False End If Next ' assuming property group was not empty Return True End If End Function Private Shared Function IsGroupOfConstructors(group As BoundMethodOrPropertyGroup) As Boolean If group.Kind = BoundKind.MethodGroup Then Dim methodGroup = DirectCast(group, BoundMethodGroup) Debug.Assert(methodGroup.Methods.Length > 0) Return methodGroup.Methods(0).MethodKind = MethodKind.Constructor End If Return False End Function Friend Function BindInvocationExpression( node As SyntaxNode, target As SyntaxNode, typeChar As TypeCharacter, group As BoundMethodOrPropertyGroup, boundArguments As ImmutableArray(Of BoundExpression), argumentNames As ImmutableArray(Of String), diagnostics As BindingDiagnosticBag, callerInfoOpt As SyntaxNode, Optional allowConstructorCall As Boolean = False, Optional suppressAbstractCallDiagnostics As Boolean = False, Optional isDefaultMemberAccess As Boolean = False, Optional representCandidateInDiagnosticsOpt As Symbol = Nothing, Optional forceExpandedForm As Boolean = False ) As BoundExpression Debug.Assert(group IsNot Nothing) Debug.Assert(allowConstructorCall OrElse Not IsGroupOfConstructors(group)) Debug.Assert(group.ResultKind = LookupResultKind.Good OrElse group.ResultKind = LookupResultKind.Inaccessible) ' It is possible to get here with method group with ResultKind = LookupResultKind.Inaccessible. ' When this happens, it is worth trying to do overload resolution on the "bad" set ' to report better errors. Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics) Dim results As OverloadResolution.OverloadResolutionResult = OverloadResolution.MethodOrPropertyInvocationOverloadResolution(group, boundArguments, argumentNames, Me, callerInfoOpt, useSiteInfo, forceExpandedForm:=forceExpandedForm) If diagnostics.Add(node, useSiteInfo) Then If group.ResultKind <> LookupResultKind.Inaccessible Then ' Suppress additional diagnostics diagnostics = BindingDiagnosticBag.Discarded End If End If If Not results.BestResult.HasValue Then If results.ResolutionIsLateBound Then Debug.Assert(OptionStrict <> VisualBasic.OptionStrict.On) ' Did we have extension methods among candidates? If group.Kind = BoundKind.MethodGroup Then Dim haveAnExtensionMethod As Boolean = False Dim methodGroup = DirectCast(group, BoundMethodGroup) For Each method As MethodSymbol In methodGroup.Methods If method.ReducedFrom IsNot Nothing Then haveAnExtensionMethod = True Exit For End If Next If Not haveAnExtensionMethod Then useSiteInfo = New CompoundUseSiteInfo(Of AssemblySymbol)(useSiteInfo) haveAnExtensionMethod = Not methodGroup.AdditionalExtensionMethods(useSiteInfo).IsEmpty diagnostics.Add(node, useSiteInfo) End If If haveAnExtensionMethod Then ReportDiagnostic(diagnostics, GetLocationForOverloadResolutionDiagnostic(node, group), ERRID.ERR_ExtensionMethodCannotBeLateBound) Dim builder = ArrayBuilder(Of BoundExpression).GetInstance() builder.Add(group) If Not boundArguments.IsEmpty Then builder.AddRange(boundArguments) End If Return New BoundBadExpression(node, LookupResultKind.OverloadResolutionFailure, ImmutableArray(Of Symbol).Empty, builder.ToImmutableAndFree(), ErrorTypeSymbol.UnknownResultType, hasErrors:=True) End If End If Return BindLateBoundInvocation(node, group, isDefaultMemberAccess, boundArguments, argumentNames, diagnostics) End If ' Create and report the diagnostic. If results.Candidates.Length = 0 Then results = OverloadResolution.MethodOrPropertyInvocationOverloadResolution(group, boundArguments, argumentNames, Me, includeEliminatedCandidates:=True, callerInfoOpt:=callerInfoOpt, useSiteInfo:=CompoundUseSiteInfo(Of AssemblySymbol).Discarded, forceExpandedForm:=forceExpandedForm) End If Return ReportOverloadResolutionFailureAndProduceBoundNode(node, group, boundArguments, argumentNames, results, diagnostics, callerInfoOpt, representCandidateInDiagnosticsOpt:=representCandidateInDiagnosticsOpt) Else Return CreateBoundCallOrPropertyAccess( node, target, typeChar, group, boundArguments, results.BestResult.Value, results.AsyncLambdaSubToFunctionMismatch, diagnostics, suppressAbstractCallDiagnostics) End If End Function Private Function CreateBoundCallOrPropertyAccess( node As SyntaxNode, target As SyntaxNode, typeChar As TypeCharacter, group As BoundMethodOrPropertyGroup, boundArguments As ImmutableArray(Of BoundExpression), bestResult As OverloadResolution.CandidateAnalysisResult, asyncLambdaSubToFunctionMismatch As ImmutableArray(Of BoundExpression), diagnostics As BindingDiagnosticBag, Optional suppressAbstractCallDiagnostics As Boolean = False ) As BoundExpression Dim candidate = bestResult.Candidate Dim methodOrProperty = candidate.UnderlyingSymbol Dim returnType = candidate.ReturnType If group.ResultKind = LookupResultKind.Inaccessible Then ReportDiagnostic(diagnostics, target, GetInaccessibleErrorInfo(bestResult.Candidate.UnderlyingSymbol)) Else Debug.Assert(group.ResultKind = LookupResultKind.Good) CheckMemberTypeAccessibility(diagnostics, node, methodOrProperty) End If diagnostics.AddRange(bestResult.TypeArgumentInferenceDiagnosticsOpt) Dim argumentInfo As (Arguments As ImmutableArray(Of BoundExpression), DefaultArguments As BitVector) = PassArguments(node, bestResult, boundArguments, diagnostics) boundArguments = argumentInfo.Arguments Debug.Assert(Not boundArguments.IsDefault) Dim hasErrors As Boolean = False Dim receiver As BoundExpression = group.ReceiverOpt If group.ResultKind = LookupResultKind.Good Then hasErrors = CheckSharedSymbolAccess(target, methodOrProperty.IsShared, receiver, group.QualificationKind, diagnostics) ' give diagnostics if sharedness is wrong. End If ReportDiagnosticsIfObsoleteOrNotSupported(diagnostics, methodOrProperty, node) hasErrors = hasErrors Or group.HasErrors If Not returnType.IsErrorType() Then VerifyTypeCharacterConsistency(node, returnType, typeChar, diagnostics) End If Dim resolvedTypeOrValueReceiver As BoundExpression = Nothing If receiver IsNot Nothing AndAlso Not hasErrors Then receiver = AdjustReceiverTypeOrValue(receiver, receiver.Syntax, methodOrProperty.IsShared, diagnostics, resolvedTypeOrValueReceiver) End If If Not suppressAbstractCallDiagnostics AndAlso receiver IsNot Nothing AndAlso (receiver.IsMyBaseReference OrElse receiver.IsMyClassReference) Then If methodOrProperty.IsMustOverride Then ' Generate an error, but continue processing ReportDiagnostic(diagnostics, group.Syntax, If(receiver.IsMyBaseReference, ERRID.ERR_MyBaseAbstractCall1, ERRID.ERR_MyClassAbstractCall1), methodOrProperty) End If End If If Not asyncLambdaSubToFunctionMismatch.IsEmpty Then For Each lambda In asyncLambdaSubToFunctionMismatch Dim errorLocation As SyntaxNode = lambda.Syntax Dim lambdaNode = TryCast(errorLocation, LambdaExpressionSyntax) If lambdaNode IsNot Nothing Then errorLocation = lambdaNode.SubOrFunctionHeader End If ReportDiagnostic(diagnostics, errorLocation, ERRID.WRN_AsyncSubCouldBeFunction) Next End If If methodOrProperty.Kind = SymbolKind.Method Then Dim method = DirectCast(methodOrProperty, MethodSymbol) Dim reducedFrom = method.ReducedFrom Dim constantValue As ConstantValue = Nothing If reducedFrom Is Nothing Then If receiver IsNot Nothing AndAlso receiver.IsPropertyOrXmlPropertyAccess() Then receiver = MakeRValue(receiver, diagnostics) End If If method.IsUserDefinedOperator() AndAlso Me.ContainingMember Is method Then ReportDiagnostic(diagnostics, target, ERRID.WRN_RecursiveOperatorCall, method) End If ' replace call with literal if possible (Chr, ChrW, Asc, AscW) constantValue = OptimizeLibraryCall(method, boundArguments, node, hasErrors, diagnostics) Else ' We are calling an extension method, prepare the receiver to be ' passed as the first parameter. receiver = UpdateReceiverForExtensionMethodOrPropertyGroup(receiver, method.ReceiverType, reducedFrom.Parameters(0), diagnostics) End If ' Remove receiver from the method group ' NOTE: we only remove it if we pass it to a new BoundCall node, ' otherwise we keep it in the group to support semantic queries Dim methodGroup = DirectCast(group, BoundMethodGroup) Dim newReceiver As BoundExpression = If(receiver IsNot Nothing, Nothing, If(resolvedTypeOrValueReceiver, methodGroup.ReceiverOpt)) methodGroup = methodGroup.Update(methodGroup.TypeArgumentsOpt, methodGroup.Methods, methodGroup.PendingExtensionMethodsOpt, methodGroup.ResultKind, newReceiver, methodGroup.QualificationKind) Return New BoundCall( node, method, methodGroup, receiver, boundArguments, constantValue, returnType, suppressObjectClone:=False, hasErrors:=hasErrors, defaultArguments:=argumentInfo.DefaultArguments) Else Dim [property] = DirectCast(methodOrProperty, PropertySymbol) Dim reducedFrom = [property].ReducedFromDefinition Debug.Assert(Not boundArguments.Any(Function(a) a.Kind = BoundKind.ByRefArgumentWithCopyBack)) If reducedFrom Is Nothing Then If receiver IsNot Nothing AndAlso receiver.IsPropertyOrXmlPropertyAccess() Then receiver = MakeRValue(receiver, diagnostics) End If Else receiver = UpdateReceiverForExtensionMethodOrPropertyGroup(receiver, [property].ReceiverType, reducedFrom.Parameters(0), diagnostics) End If ' Remove receiver from the property group ' NOTE: we only remove it if we pass it to a new BoundPropertyAccess node, ' otherwise we keep it in the group to support semantic queries Dim propertyGroup = DirectCast(group, BoundPropertyGroup) Dim newReceiver As BoundExpression = If(receiver IsNot Nothing, Nothing, If(resolvedTypeOrValueReceiver, propertyGroup.ReceiverOpt)) propertyGroup = propertyGroup.Update(propertyGroup.Properties, propertyGroup.ResultKind, newReceiver, propertyGroup.QualificationKind) Return New BoundPropertyAccess( node, [property], propertyGroup, PropertyAccessKind.Unknown, [property].IsWritable(receiver, Me, isKnownTargetOfObjectMemberInitializer:=False), receiver, boundArguments, argumentInfo.DefaultArguments, hasErrors:=hasErrors) End If End Function Friend Sub WarnOnRecursiveAccess(propertyAccess As BoundPropertyAccess, accessKind As PropertyAccessKind, diagnostics As BindingDiagnosticBag) Dim [property] As PropertySymbol = propertyAccess.PropertySymbol If [property].ReducedFromDefinition Is Nothing AndAlso [property].ParameterCount = 0 AndAlso ([property].IsShared OrElse (propertyAccess.ReceiverOpt IsNot Nothing AndAlso propertyAccess.ReceiverOpt.Kind = BoundKind.MeReference)) Then Dim reportRecursiveCall As Boolean = False If [property].GetMethod Is ContainingMember Then If (accessKind And PropertyAccessKind.Get) <> 0 AndAlso (propertyAccess.AccessKind And PropertyAccessKind.Get) = 0 Then reportRecursiveCall = True End If ElseIf [property].SetMethod Is ContainingMember Then If (accessKind And PropertyAccessKind.Set) <> 0 AndAlso (propertyAccess.AccessKind And PropertyAccessKind.Set) = 0 Then reportRecursiveCall = True End If End If If reportRecursiveCall Then ReportDiagnostic(diagnostics, propertyAccess.Syntax, ERRID.WRN_RecursivePropertyCall, [property]) End If End If End Sub Friend Sub WarnOnRecursiveAccess(node As BoundExpression, accessKind As PropertyAccessKind, diagnostics As BindingDiagnosticBag) Select Case node.Kind Case BoundKind.XmlMemberAccess ' Nothing to do Case BoundKind.PropertyAccess WarnOnRecursiveAccess(DirectCast(node, BoundPropertyAccess), accessKind, diagnostics) Case Else Throw ExceptionUtilities.UnexpectedValue(node.Kind) End Select End Sub Private Function UpdateReceiverForExtensionMethodOrPropertyGroup( receiver As BoundExpression, targetType As TypeSymbol, thisParameterDefinition As ParameterSymbol, diagnostics As BindingDiagnosticBag ) As BoundExpression If receiver IsNot Nothing AndAlso receiver.IsValue AndAlso Not targetType.IsErrorType() AndAlso Not receiver.Type.IsErrorType() Then Dim oldReceiver As BoundExpression = receiver Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics) receiver = PassArgument(receiver, Conversions.ClassifyConversion(receiver, targetType, Me, useSiteInfo), False, Conversions.ClassifyConversion(targetType, receiver.Type, useSiteInfo), targetType, thisParameterDefinition, diagnostics) diagnostics.Add(receiver, useSiteInfo) If oldReceiver.WasCompilerGenerated AndAlso receiver IsNot oldReceiver Then Select Case oldReceiver.Kind Case BoundKind.MeReference, BoundKind.WithLValueExpressionPlaceholder, BoundKind.WithRValueExpressionPlaceholder receiver.SetWasCompilerGenerated() End Select End If End If Return receiver End Function Private Function IsWellKnownTypeMember(memberId As WellKnownMember, method As MethodSymbol) As Boolean Return Compilation.GetWellKnownTypeMember(memberId) Is method End Function ''' <summary> ''' Optimizes some runtime library calls through replacing them with a literal if possible. ''' VB Spec 11.2 defines the following runtime functions as being constant: ''' - Microsoft.VisualBasic.Strings.ChrW ''' - Microsoft.VisualBasic.Strings.Chr, if the constant value is between 0 and 128 ''' - Microsoft.VisualBasic.Strings.AscW, if the constant string is not empty ''' - Microsoft.VisualBasic.Strings.Asc, if the constant string is not empty ''' </summary> ''' <param name="method">The method.</param> ''' <param name="arguments">The arguments of the method call.</param> ''' <param name="syntax">The syntax node for report errors.</param> ''' <param name="diagnostics">The diagnostics.</param> ''' <param name="hasErrors">Set to true if there are conversion errors (e.g. Asc("")). Otherwise it's not written to.</param> ''' <returns>The constant value that replaces this node, or nothing.</returns> Private Function OptimizeLibraryCall( method As MethodSymbol, arguments As ImmutableArray(Of BoundExpression), syntax As SyntaxNode, ByRef hasErrors As Boolean, diagnostics As BindingDiagnosticBag ) As ConstantValue ' cheapest way to filter out methods that do not match If arguments.Length = 1 AndAlso arguments(0).IsConstant AndAlso Not arguments(0).ConstantValueOpt.IsBad Then ' only continue checking if containing type is Microsoft.VisualBasic.Strings If Compilation.GetWellKnownType(WellKnownType.Microsoft_VisualBasic_Strings) IsNot method.ContainingType Then Return Nothing End If ' AscW(char) / AscW(String) ' all values can be optimized as a literal, except an empty string that produces a diagnostic If IsWellKnownTypeMember(WellKnownMember.Microsoft_VisualBasic_Strings__AscWCharInt32, method) OrElse IsWellKnownTypeMember(WellKnownMember.Microsoft_VisualBasic_Strings__AscWStringInt32, method) Then Dim argumentConstantValue = arguments(0).ConstantValueOpt Dim argumentValue As String If argumentConstantValue.IsNull Then argumentValue = String.Empty ElseIf argumentConstantValue.IsChar Then argumentValue = argumentConstantValue.CharValue Else Debug.Assert(argumentConstantValue.IsString()) argumentValue = argumentConstantValue.StringValue End If If argumentValue.IsEmpty() Then ReportDiagnostic(diagnostics, syntax, ERRID.ERR_CannotConvertValue2, argumentValue, method.ReturnType) hasErrors = True Return Nothing End If Return ConstantValue.Create(AscW(argumentValue)) End If ' ChrW ' for -32768 < value or value > 65535 we show a diagnostic If IsWellKnownTypeMember(WellKnownMember.Microsoft_VisualBasic_Strings__ChrWInt32Char, method) Then Dim argumentValue = arguments(0).ConstantValueOpt.Int32Value If argumentValue < -32768 OrElse argumentValue > 65535 Then ReportDiagnostic(diagnostics, syntax, ERRID.ERR_CannotConvertValue2, argumentValue, method.ReturnType) hasErrors = True Return Nothing End If Return ConstantValue.Create(ChrW(argumentValue)) End If ' Asc(Char) / Asc(String) ' all values from 0 to 127 can be optimized to a literal. If IsWellKnownTypeMember(WellKnownMember.Microsoft_VisualBasic_Strings__AscCharInt32, method) OrElse IsWellKnownTypeMember(WellKnownMember.Microsoft_VisualBasic_Strings__AscStringInt32, method) Then Dim constantValue = arguments(0).ConstantValueOpt Dim argumentValue As String If constantValue.IsNull Then argumentValue = String.Empty ElseIf constantValue.IsChar Then argumentValue = constantValue.CharValue Else Debug.Assert(constantValue.IsString()) argumentValue = constantValue.StringValue End If If argumentValue.IsEmpty() Then ReportDiagnostic(diagnostics, syntax, ERRID.ERR_CannotConvertValue2, argumentValue, method.ReturnType) hasErrors = True Return Nothing End If ' we are only folding 7bit ASCII chars, so it's ok to use AscW here, although this is the Asc folding. Dim charValue = AscW(argumentValue) If charValue < 128 Then Return ConstantValue.Create(charValue) End If Return Nothing End If ' Chr ' values from 0 to 127 can be optimized as a literal ' for -32768 < value or value > 65535 we show a diagnostic If IsWellKnownTypeMember(WellKnownMember.Microsoft_VisualBasic_Strings__ChrInt32Char, method) Then Dim argumentValue = arguments(0).ConstantValueOpt.Int32Value If argumentValue >= 0 AndAlso argumentValue < 128 Then Return ConstantValue.Create(ChrW(argumentValue)) ElseIf argumentValue < -32768 OrElse argumentValue > 65535 Then ReportDiagnostic(diagnostics, syntax, ERRID.ERR_CannotConvertValue2, argumentValue, method.ReturnType) hasErrors = True Return Nothing End If End If End If Return Nothing End Function Private Function ReportOverloadResolutionFailureAndProduceBoundNode( node As SyntaxNode, group As BoundMethodOrPropertyGroup, boundArguments As ImmutableArray(Of BoundExpression), argumentNames As ImmutableArray(Of String), <[In]> ByRef results As OverloadResolution.OverloadResolutionResult, diagnostics As BindingDiagnosticBag, callerInfoOpt As SyntaxNode, Optional overrideCommonReturnType As TypeSymbol = Nothing, Optional queryMode As Boolean = False, Optional boundTypeExpression As BoundTypeExpression = Nothing, Optional representCandidateInDiagnosticsOpt As Symbol = Nothing, Optional diagnosticLocationOpt As Location = Nothing ) As BoundExpression Return ReportOverloadResolutionFailureAndProduceBoundNode( node, group.ResultKind, boundArguments, argumentNames, results, diagnostics, callerInfoOpt, group, overrideCommonReturnType, queryMode, boundTypeExpression, representCandidateInDiagnosticsOpt, diagnosticLocationOpt) End Function Private Function ReportOverloadResolutionFailureAndProduceBoundNode( node As SyntaxNode, lookupResult As LookupResultKind, boundArguments As ImmutableArray(Of BoundExpression), argumentNames As ImmutableArray(Of String), <[In]> ByRef results As OverloadResolution.OverloadResolutionResult, diagnostics As BindingDiagnosticBag, callerInfoOpt As SyntaxNode, Optional groupOpt As BoundMethodOrPropertyGroup = Nothing, Optional overrideCommonReturnType As TypeSymbol = Nothing, Optional queryMode As Boolean = False, Optional boundTypeExpression As BoundTypeExpression = Nothing, Optional representCandidateInDiagnosticsOpt As Symbol = Nothing, Optional diagnosticLocationOpt As Location = Nothing ) As BoundExpression Dim bestCandidates = ArrayBuilder(Of OverloadResolution.CandidateAnalysisResult).GetInstance() Dim bestSymbols = ImmutableArray(Of Symbol).Empty Dim commonReturnType As TypeSymbol = GetSetOfTheBestCandidates(results, bestCandidates, bestSymbols) If overrideCommonReturnType IsNot Nothing Then commonReturnType = overrideCommonReturnType End If Dim result As BoundExpression = ReportOverloadResolutionFailureAndProduceBoundNode( node, lookupResult, bestCandidates, bestSymbols, commonReturnType, boundArguments, argumentNames, diagnostics, callerInfoOpt, groupOpt, Nothing, queryMode, boundTypeExpression, representCandidateInDiagnosticsOpt, diagnosticLocationOpt) bestCandidates.Free() Return result End Function Private Function ReportOverloadResolutionFailureAndProduceBoundNode( node As SyntaxNode, group As BoundMethodOrPropertyGroup, bestCandidates As ArrayBuilder(Of OverloadResolution.CandidateAnalysisResult), bestSymbols As ImmutableArray(Of Symbol), commonReturnType As TypeSymbol, boundArguments As ImmutableArray(Of BoundExpression), argumentNames As ImmutableArray(Of String), diagnostics As BindingDiagnosticBag, callerInfoOpt As SyntaxNode, Optional delegateSymbol As Symbol = Nothing, Optional queryMode As Boolean = False, Optional boundTypeExpression As BoundTypeExpression = Nothing, Optional representCandidateInDiagnosticsOpt As Symbol = Nothing ) As BoundExpression Return ReportOverloadResolutionFailureAndProduceBoundNode( node, group.ResultKind, bestCandidates, bestSymbols, commonReturnType, boundArguments, argumentNames, diagnostics, callerInfoOpt, group, delegateSymbol, queryMode, boundTypeExpression, representCandidateInDiagnosticsOpt) End Function Public Shared Function GetLocationForOverloadResolutionDiagnostic(node As SyntaxNode, Optional groupOpt As BoundMethodOrPropertyGroup = Nothing) As Location Dim result As SyntaxNode If groupOpt IsNot Nothing Then If node.SyntaxTree Is groupOpt.Syntax.SyntaxTree AndAlso node.Span.Contains(groupOpt.Syntax.Span) Then result = groupOpt.Syntax If result Is node AndAlso (groupOpt.ReceiverOpt Is Nothing OrElse groupOpt.ReceiverOpt.Syntax Is result) Then Return result.GetLocation() End If Else Return node.GetLocation() End If ElseIf node.IsKind(SyntaxKind.InvocationExpression) Then result = If(DirectCast(node, InvocationExpressionSyntax).Expression, node) Else Return node.GetLocation() End If Select Case result.Kind Case SyntaxKind.QualifiedName Return DirectCast(result, QualifiedNameSyntax).Right.GetLocation() Case SyntaxKind.SimpleMemberAccessExpression If result.Parent IsNot Nothing AndAlso result.Parent.IsKind(SyntaxKind.AddressOfExpression) Then Return result.GetLocation() End If Return DirectCast(result, MemberAccessExpressionSyntax).Name.GetLocation() Case SyntaxKind.XmlElementAccessExpression, SyntaxKind.XmlDescendantAccessExpression, SyntaxKind.XmlAttributeAccessExpression Return DirectCast(result, XmlMemberAccessExpressionSyntax).Name.GetLocation() Case SyntaxKind.HandlesClauseItem Return DirectCast(result, HandlesClauseItemSyntax).EventMember.GetLocation() End Select Return result.GetLocation() End Function Private Function ReportOverloadResolutionFailureAndProduceBoundNode( node As SyntaxNode, lookupResult As LookupResultKind, bestCandidates As ArrayBuilder(Of OverloadResolution.CandidateAnalysisResult), bestSymbols As ImmutableArray(Of Symbol), commonReturnType As TypeSymbol, boundArguments As ImmutableArray(Of BoundExpression), argumentNames As ImmutableArray(Of String), diagnostics As BindingDiagnosticBag, callerInfoOpt As SyntaxNode, Optional groupOpt As BoundMethodOrPropertyGroup = Nothing, Optional delegateSymbol As Symbol = Nothing, Optional queryMode As Boolean = False, Optional boundTypeExpression As BoundTypeExpression = Nothing, Optional representCandidateInDiagnosticsOpt As Symbol = Nothing, Optional diagnosticLocationOpt As Location = Nothing ) As BoundExpression Debug.Assert(commonReturnType IsNot Nothing AndAlso bestSymbols.Length > 0 AndAlso bestCandidates.Count >= bestSymbols.Length) Debug.Assert(groupOpt Is Nothing OrElse lookupResult = groupOpt.ResultKind) Dim state = OverloadResolution.CandidateAnalysisResultState.Count If bestCandidates.Count > 0 Then state = bestCandidates(0).State End If If boundArguments.IsDefault Then boundArguments = ImmutableArray(Of BoundExpression).Empty End If Dim singleCandidateAnalysisResult As OverloadResolution.CandidateAnalysisResult = Nothing Dim singleCandidate As OverloadResolution.Candidate = Nothing Dim allowUnexpandedParamArrayForm As Boolean = False Dim allowExpandedParamArrayForm As Boolean = False ' Figure out if we should report single candidate errors If bestSymbols.Length = 1 AndAlso bestCandidates.Count < 3 Then singleCandidateAnalysisResult = bestCandidates(0) singleCandidate = singleCandidateAnalysisResult.Candidate allowExpandedParamArrayForm = singleCandidateAnalysisResult.IsExpandedParamArrayForm allowUnexpandedParamArrayForm = Not allowExpandedParamArrayForm If bestCandidates.Count > 1 Then If bestCandidates(1).IsExpandedParamArrayForm Then allowExpandedParamArrayForm = True Else allowUnexpandedParamArrayForm = True End If End If End If If lookupResult = LookupResultKind.Inaccessible Then If singleCandidate IsNot Nothing Then ReportDiagnostic(diagnostics, If(groupOpt IsNot Nothing, groupOpt.Syntax, node), GetInaccessibleErrorInfo(singleCandidate.UnderlyingSymbol)) Else If Not queryMode Then ReportDiagnostic(diagnostics, If(groupOpt IsNot Nothing, groupOpt.Syntax, node), ERRID.ERR_NoViableOverloadCandidates1, bestSymbols(0).Name) End If ' Do not report more errors. GoTo ProduceBoundNode End If Else Debug.Assert(lookupResult = LookupResultKind.Good) End If If diagnosticLocationOpt Is Nothing Then diagnosticLocationOpt = GetLocationForOverloadResolutionDiagnostic(node, groupOpt) End If ' Report diagnostic according to the state of candidates Select Case state Case VisualBasic.OverloadResolution.CandidateAnalysisResultState.HasUseSiteError, OverloadResolution.CandidateAnalysisResultState.HasUnsupportedMetadata If singleCandidate IsNot Nothing Then ReportOverloadResolutionFailureForASingleCandidate(node, diagnosticLocationOpt, lookupResult, singleCandidateAnalysisResult, boundArguments, argumentNames, allowUnexpandedParamArrayForm, allowExpandedParamArrayForm, True, False, diagnostics, delegateSymbol:=delegateSymbol, queryMode:=queryMode, callerInfoOpt:=callerInfoOpt, representCandidateInDiagnosticsOpt:=representCandidateInDiagnosticsOpt) Else ReportOverloadResolutionFailureForASetOfCandidates(node, diagnosticLocationOpt, lookupResult, ERRID.ERR_BadOverloadCandidates2, bestCandidates, boundArguments, argumentNames, diagnostics, delegateSymbol:=delegateSymbol, queryMode:=queryMode, callerInfoOpt:=callerInfoOpt) End If Case VisualBasic.OverloadResolution.CandidateAnalysisResultState.Ambiguous Dim candidate As Symbol = bestSymbols(0).OriginalDefinition Dim container As Symbol = candidate.ContainingSymbol ReportDiagnostic(diagnostics, diagnosticLocationOpt, ERRID.ERR_MetadataMembersAmbiguous3, candidate.Name, container.GetKindText(), container) Case OverloadResolution.CandidateAnalysisResultState.BadGenericArity Debug.Assert(groupOpt IsNot Nothing AndAlso groupOpt.Kind = BoundKind.MethodGroup) Dim mg = DirectCast(groupOpt, BoundMethodGroup) If singleCandidate IsNot Nothing Then Dim typeArguments = If(mg.TypeArgumentsOpt IsNot Nothing, mg.TypeArgumentsOpt.Arguments, ImmutableArray(Of TypeSymbol).Empty) If typeArguments.IsDefault Then typeArguments = ImmutableArray(Of TypeSymbol).Empty End If Dim singleSymbol As Symbol = singleCandidate.UnderlyingSymbol Dim isExtension As Boolean = singleCandidate.IsExtensionMethod If singleCandidate.Arity < typeArguments.Length Then If isExtension Then ReportDiagnostic(diagnostics, mg.TypeArgumentsOpt.Syntax, If(singleCandidate.Arity = 0, ERRID.ERR_TypeOrMemberNotGeneric2, ERRID.ERR_TooManyGenericArguments2), singleSymbol, singleSymbol.ContainingType) Else ReportDiagnostic(diagnostics, mg.TypeArgumentsOpt.Syntax, If(singleCandidate.Arity = 0, ERRID.ERR_TypeOrMemberNotGeneric1, ERRID.ERR_TooManyGenericArguments1), singleSymbol) End If Else Debug.Assert(singleCandidate.Arity > typeArguments.Length) If isExtension Then ReportDiagnostic(diagnostics, mg.TypeArgumentsOpt.Syntax, ERRID.ERR_TooFewGenericArguments2, singleSymbol, singleSymbol.ContainingType) Else ReportDiagnostic(diagnostics, mg.TypeArgumentsOpt.Syntax, ERRID.ERR_TooFewGenericArguments1, singleSymbol) End If End If Else ReportDiagnostic(diagnostics, diagnosticLocationOpt, ERRID.ERR_NoTypeArgumentCountOverloadCand1, CustomSymbolDisplayFormatter.ShortErrorName(bestSymbols(0))) End If Case OverloadResolution.CandidateAnalysisResultState.ArgumentCountMismatch If node.Kind = SyntaxKind.IdentifierName AndAlso node.Parent IsNot Nothing AndAlso node.Parent.Kind = SyntaxKind.NamedFieldInitializer AndAlso groupOpt IsNot Nothing AndAlso groupOpt.Kind = BoundKind.PropertyGroup Then ' report special diagnostics for a failed overload resolution because all available properties ' require arguments in case this method was called while binding a object member initializer. ReportDiagnostic(diagnostics, diagnosticLocationOpt, If(singleCandidate IsNot Nothing, ERRID.ERR_ParameterizedPropertyInAggrInit1, ERRID.ERR_NoZeroCountArgumentInitCandidates1), CustomSymbolDisplayFormatter.ShortErrorName(bestSymbols(0))) Else If singleCandidate IsNot Nothing AndAlso (Not queryMode OrElse singleCandidate.ParameterCount <= boundArguments.Length) Then ReportOverloadResolutionFailureForASingleCandidate(node, diagnosticLocationOpt, lookupResult, singleCandidateAnalysisResult, boundArguments, argumentNames, allowUnexpandedParamArrayForm, allowExpandedParamArrayForm, True, False, diagnostics, delegateSymbol:=delegateSymbol, queryMode:=queryMode, callerInfoOpt:=callerInfoOpt, representCandidateInDiagnosticsOpt:=representCandidateInDiagnosticsOpt) Else ReportDiagnostic(diagnostics, diagnosticLocationOpt, ERRID.ERR_NoArgumentCountOverloadCandidates1, CustomSymbolDisplayFormatter.ShortErrorName(bestSymbols(0))) End If End If Case OverloadResolution.CandidateAnalysisResultState.ArgumentMismatch, OverloadResolution.CandidateAnalysisResultState.GenericConstraintsViolated Dim haveBadArgument As Boolean = False For i As Integer = 0 To boundArguments.Length - 1 Step 1 Dim type = boundArguments(i).Type If boundArguments(i).HasErrors OrElse (type IsNot Nothing AndAlso type.IsErrorType()) Then haveBadArgument = True Exit For End If Next If Not haveBadArgument Then If singleCandidate IsNot Nothing Then ReportOverloadResolutionFailureForASingleCandidate(node, diagnosticLocationOpt, lookupResult, singleCandidateAnalysisResult, boundArguments, argumentNames, allowUnexpandedParamArrayForm, allowExpandedParamArrayForm, True, False, diagnostics, delegateSymbol:=delegateSymbol, queryMode:=queryMode, callerInfoOpt:=callerInfoOpt, representCandidateInDiagnosticsOpt:=representCandidateInDiagnosticsOpt) Else ReportOverloadResolutionFailureForASetOfCandidates(node, diagnosticLocationOpt, lookupResult, If(delegateSymbol Is Nothing, ERRID.ERR_NoCallableOverloadCandidates2, ERRID.ERR_DelegateBindingFailure3), bestCandidates, boundArguments, argumentNames, diagnostics, delegateSymbol:=delegateSymbol, queryMode:=queryMode, callerInfoOpt:=callerInfoOpt) End If End If Case OverloadResolution.CandidateAnalysisResultState.TypeInferenceFailed If singleCandidate IsNot Nothing Then ReportOverloadResolutionFailureForASingleCandidate(node, diagnosticLocationOpt, lookupResult, singleCandidateAnalysisResult, boundArguments, argumentNames, allowUnexpandedParamArrayForm, allowExpandedParamArrayForm, True, False, diagnostics, delegateSymbol:=delegateSymbol, queryMode:=queryMode, callerInfoOpt:=callerInfoOpt, representCandidateInDiagnosticsOpt:=representCandidateInDiagnosticsOpt) Else ReportOverloadResolutionFailureForASetOfCandidates(node, diagnosticLocationOpt, lookupResult, ERRID.ERR_NoCallableOverloadCandidates2, bestCandidates, boundArguments, argumentNames, diagnostics, delegateSymbol:=delegateSymbol, queryMode:=queryMode, callerInfoOpt:=callerInfoOpt) End If Case OverloadResolution.CandidateAnalysisResultState.Applicable ' it is only possible to get overloading failure with a single candidate ' if we have a paramarray with equally specific virtual signatures Debug.Assert(singleCandidate Is Nothing OrElse singleCandidate.ParameterCount <> 0 AndAlso singleCandidate.Parameters(singleCandidate.ParameterCount - 1).IsParamArray) If bestCandidates(0).RequiresNarrowingConversion Then ReportOverloadResolutionFailureForASetOfCandidates(node, diagnosticLocationOpt, lookupResult, If(delegateSymbol Is Nothing, ERRID.ERR_NoNonNarrowingOverloadCandidates2, ERRID.ERR_DelegateBindingFailure3), bestCandidates, boundArguments, argumentNames, diagnostics, delegateSymbol:=delegateSymbol, queryMode:=queryMode, callerInfoOpt:=callerInfoOpt) Else ReportUnspecificProcedures(diagnosticLocationOpt, bestSymbols, diagnostics, (delegateSymbol IsNot Nothing)) End If Case Else ' Unexpected Throw ExceptionUtilities.UnexpectedValue(state) End Select ProduceBoundNode: Dim childBoundNodes As ImmutableArray(Of BoundExpression) If boundArguments.IsEmpty AndAlso boundTypeExpression Is Nothing Then If groupOpt Is Nothing Then childBoundNodes = ImmutableArray(Of BoundExpression).Empty Else childBoundNodes = ImmutableArray.Create(Of BoundExpression)(groupOpt) End If Else Dim builder = ArrayBuilder(Of BoundExpression).GetInstance() If groupOpt IsNot Nothing Then builder.Add(groupOpt) End If If Not boundArguments.IsEmpty Then builder.AddRange(boundArguments) End If If boundTypeExpression IsNot Nothing Then builder.Add(boundTypeExpression) End If childBoundNodes = builder.ToImmutableAndFree() End If Dim resultKind = LookupResultKind.OverloadResolutionFailure If lookupResult < resultKind Then resultKind = lookupResult End If Return New BoundBadExpression(node, resultKind, bestSymbols, childBoundNodes, commonReturnType, hasErrors:=True) End Function ''' <summary> '''Figure out the set of best candidates in the following preference order: ''' 1) Applicable ''' 2) ArgumentMismatch, GenericConstraintsViolated ''' 3) TypeInferenceFailed ''' 4) ArgumentCountMismatch ''' 5) BadGenericArity ''' 6) Ambiguous ''' 7) HasUseSiteError ''' 8) HasUnsupportedMetadata ''' ''' Also return the set of unique symbols behind the set. ''' ''' Returns type symbol for the common type, if any. ''' Otherwise returns ErrorTypeSymbol.UnknownResultType. ''' </summary> Private Shared Function GetSetOfTheBestCandidates( ByRef results As OverloadResolution.OverloadResolutionResult, bestCandidates As ArrayBuilder(Of OverloadResolution.CandidateAnalysisResult), ByRef bestSymbols As ImmutableArray(Of Symbol) ) As TypeSymbol Const Applicable = OverloadResolution.CandidateAnalysisResultState.Applicable Const ArgumentMismatch = OverloadResolution.CandidateAnalysisResultState.ArgumentMismatch Const GenericConstraintsViolated = OverloadResolution.CandidateAnalysisResultState.GenericConstraintsViolated Const TypeInferenceFailed = OverloadResolution.CandidateAnalysisResultState.TypeInferenceFailed Const ArgumentCountMismatch = OverloadResolution.CandidateAnalysisResultState.ArgumentCountMismatch Const BadGenericArity = OverloadResolution.CandidateAnalysisResultState.BadGenericArity Const Ambiguous = OverloadResolution.CandidateAnalysisResultState.Ambiguous Const HasUseSiteError = OverloadResolution.CandidateAnalysisResultState.HasUseSiteError Const HasUnsupportedMetadata = OverloadResolution.CandidateAnalysisResultState.HasUnsupportedMetadata Dim preference(OverloadResolution.CandidateAnalysisResultState.Count - 1) As Integer preference(Applicable) = 1 preference(ArgumentMismatch) = 2 preference(GenericConstraintsViolated) = 2 preference(TypeInferenceFailed) = 3 preference(ArgumentCountMismatch) = 4 preference(BadGenericArity) = 5 preference(Ambiguous) = 6 preference(HasUseSiteError) = 7 preference(HasUnsupportedMetadata) = 8 For Each candidate In results.Candidates Dim prefNew = preference(candidate.State) If prefNew <> 0 Then If bestCandidates.Count = 0 Then bestCandidates.Add(candidate) Else Dim prefOld = preference(bestCandidates(0).State) If prefNew = prefOld Then bestCandidates.Add(candidate) ElseIf prefNew < prefOld Then bestCandidates.Clear() bestCandidates.Add(candidate) End If End If End If Next ' Collect unique best symbols. Dim bestSymbolsBuilder = ArrayBuilder(Of Symbol).GetInstance(bestCandidates.Count) Dim commonReturnType As TypeSymbol = Nothing If bestCandidates.Count = 1 Then ' For multiple candidates we never pick common type that refers to method's type parameter ' because each method has distinct type parameters. For single candidate case we need to ' ensure this explicitly. Dim underlyingSymbol As Symbol = bestCandidates(0).Candidate.UnderlyingSymbol bestSymbolsBuilder.Add(underlyingSymbol) commonReturnType = bestCandidates(0).Candidate.ReturnType If underlyingSymbol.Kind = SymbolKind.Method Then Dim method = DirectCast(underlyingSymbol, MethodSymbol) If method.IsGenericMethod AndAlso commonReturnType.ReferencesMethodsTypeParameter(method) Then Select Case CInt(bestCandidates(0).State) Case TypeInferenceFailed, HasUseSiteError, HasUnsupportedMetadata, BadGenericArity, ArgumentCountMismatch commonReturnType = Nothing End Select End If End If Else For i As Integer = 0 To bestCandidates.Count - 1 Step 1 If i = 0 OrElse Not bestSymbolsBuilder(bestSymbolsBuilder.Count - 1).Equals(bestCandidates(i).Candidate.UnderlyingSymbol) Then bestSymbolsBuilder.Add(bestCandidates(i).Candidate.UnderlyingSymbol) Dim returnType = bestCandidates(i).Candidate.ReturnType If commonReturnType Is Nothing Then commonReturnType = returnType ElseIf commonReturnType IsNot ErrorTypeSymbol.UnknownResultType AndAlso Not commonReturnType.IsSameTypeIgnoringAll(returnType) Then commonReturnType = ErrorTypeSymbol.UnknownResultType End If End If Next End If bestSymbols = bestSymbolsBuilder.ToImmutableAndFree() Return If(commonReturnType, ErrorTypeSymbol.UnknownResultType) End Function Private Shared Sub ReportUnspecificProcedures( diagnosticLocation As Location, bestSymbols As ImmutableArray(Of Symbol), diagnostics As BindingDiagnosticBag, isDelegateContext As Boolean ) Dim diagnosticInfos = ArrayBuilder(Of DiagnosticInfo).GetInstance(bestSymbols.Length) Dim notMostSpecificMessage = ErrorFactory.ErrorInfo(ERRID.ERR_NotMostSpecificOverload) Dim withContainingTypeInDiagnostics As Boolean = False If Not bestSymbols(0).IsReducedExtensionMethod Then Dim container As NamedTypeSymbol = bestSymbols(0).ContainingType For i As Integer = 1 To bestSymbols.Length - 1 Step 1 If Not TypeSymbol.Equals(bestSymbols(i).ContainingType, container, TypeCompareKind.ConsiderEverything) Then withContainingTypeInDiagnostics = True End If Next End If For i As Integer = 0 To bestSymbols.Length - 1 Step 1 ' in delegate context we just output for each candidates ' BC30794: No accessible 'goo' is most specific: ' Public Sub goo(p As Integer) ' Public Sub goo(p As Integer) ' ' in other contexts we give more information, e.g. ' BC30794: No accessible 'goo' is most specific: ' Public Sub goo(p As Integer): <reason> ' Public Sub goo(p As Integer): <reason> Dim bestSymbol As Symbol = bestSymbols(i) Dim bestSymbolIsExtension As Boolean = bestSymbol.IsReducedExtensionMethod If isDelegateContext Then If bestSymbolIsExtension Then diagnosticInfos.Add(ErrorFactory.ErrorInfo(ERRID.ERR_ExtensionMethodOverloadCandidate2, bestSymbol, bestSymbol.ContainingType)) ElseIf withContainingTypeInDiagnostics Then diagnosticInfos.Add(ErrorFactory.ErrorInfo(ERRID.ERR_OverloadCandidate1, CustomSymbolDisplayFormatter.WithContainingType(bestSymbol))) Else diagnosticInfos.Add(ErrorFactory.ErrorInfo(ERRID.ERR_OverloadCandidate1, bestSymbol)) End If Else If bestSymbolIsExtension Then diagnosticInfos.Add(ErrorFactory.ErrorInfo(ERRID.ERR_ExtensionMethodOverloadCandidate3, bestSymbol, bestSymbol.ContainingType, notMostSpecificMessage)) ElseIf withContainingTypeInDiagnostics Then diagnosticInfos.Add(ErrorFactory.ErrorInfo(ERRID.ERR_OverloadCandidate2, CustomSymbolDisplayFormatter.WithContainingType(bestSymbol), notMostSpecificMessage)) Else diagnosticInfos.Add(ErrorFactory.ErrorInfo(ERRID.ERR_OverloadCandidate2, bestSymbol, notMostSpecificMessage)) End If End If Next ReportDiagnostic(diagnostics, diagnosticLocation, ErrorFactory.ErrorInfo(If(isDelegateContext, ERRID.ERR_AmbiguousDelegateBinding2, ERRID.ERR_NoMostSpecificOverload2), CustomSymbolDisplayFormatter.ShortErrorName(bestSymbols(0)), New CompoundDiagnosticInfo(diagnosticInfos.ToArrayAndFree()) )) End Sub Private Sub ReportOverloadResolutionFailureForASetOfCandidates( node As SyntaxNode, diagnosticLocation As Location, lookupResult As LookupResultKind, errorNo As ERRID, candidates As ArrayBuilder(Of OverloadResolution.CandidateAnalysisResult), arguments As ImmutableArray(Of BoundExpression), argumentNames As ImmutableArray(Of String), diagnostics As BindingDiagnosticBag, delegateSymbol As Symbol, queryMode As Boolean, callerInfoOpt As SyntaxNode ) Dim diagnosticPerSymbol = ArrayBuilder(Of KeyValuePair(Of Symbol, ReadOnlyBindingDiagnostic(Of AssemblySymbol))).GetInstance(candidates.Count) If arguments.IsDefault Then arguments = ImmutableArray(Of BoundExpression).Empty End If For i As Integer = 0 To candidates.Count - 1 Step 1 ' See if we need to consider both expanded and unexpanded version of the same method. ' We want to report only one set of errors in this case. ' Note, that, when OverloadResolution collects candidates expanded form always ' immediately follows unexpanded form, if both should be considered. Dim allowExpandedParamArrayForm As Boolean = candidates(i).IsExpandedParamArrayForm Dim allowUnexpandedParamArrayForm As Boolean = Not allowExpandedParamArrayForm If allowUnexpandedParamArrayForm AndAlso i + 1 < candidates.Count AndAlso candidates(i + 1).IsExpandedParamArrayForm AndAlso candidates(i + 1).Candidate.UnderlyingSymbol.Equals(candidates(i).Candidate.UnderlyingSymbol) Then allowExpandedParamArrayForm = True i += 1 End If Dim candidateDiagnostics = BindingDiagnosticBag.GetInstance(diagnostics) ' Collect diagnostic for this candidate ReportOverloadResolutionFailureForASingleCandidate(node, diagnosticLocation, lookupResult, candidates(i), arguments, argumentNames, allowUnexpandedParamArrayForm, allowExpandedParamArrayForm, False, errorNo = If(delegateSymbol Is Nothing, ERRID.ERR_NoNonNarrowingOverloadCandidates2, ERRID.ERR_DelegateBindingFailure3), candidateDiagnostics, delegateSymbol:=delegateSymbol, queryMode:=queryMode, callerInfoOpt:=callerInfoOpt, representCandidateInDiagnosticsOpt:=Nothing) diagnosticPerSymbol.Add(KeyValuePair.Create(candidates(i).Candidate.UnderlyingSymbol, candidateDiagnostics.ToReadOnlyAndFree())) Next ' See if there are errors that are reported for each candidate at the same location within a lambda argument. ' Report them and don't report remaining diagnostics for each symbol separately. If Not ReportCommonErrorsFromLambdas(diagnosticPerSymbol, arguments, diagnostics) Then Dim diagnosticInfos = ArrayBuilder(Of DiagnosticInfo).GetInstance(candidates.Count) For i As Integer = 0 To diagnosticPerSymbol.Count - 1 Dim symbol = diagnosticPerSymbol(i).Key Dim isExtension As Boolean = symbol.IsReducedExtensionMethod() Dim sealedCandidateDiagnostics = diagnosticPerSymbol(i).Value.Diagnostics ' When reporting errors for an AddressOf, Dev 10 shows different error messages depending on how many ' errors there are per candidate. ' One narrowing error will be shown like: ' 'Public Sub goo6(p As Integer, p2 As Byte)': Option Strict On disallows implicit conversions from 'Integer' to 'Byte'. ' More than one narrowing issues in the parameters are abbreviated with: ' 'Public Sub goo6(p As Byte, p2 As Byte)': Method does not have a signature compatible with the delegate. If delegateSymbol Is Nothing OrElse Not sealedCandidateDiagnostics.Skip(1).Any() Then If isExtension Then For Each iDiagnostic In sealedCandidateDiagnostics diagnosticInfos.Add(ErrorFactory.ErrorInfo(ERRID.ERR_ExtensionMethodOverloadCandidate3, symbol, symbol.ContainingType, DirectCast(iDiagnostic, DiagnosticWithInfo).Info)) Next Else For Each iDiagnostic In sealedCandidateDiagnostics Dim msg = VisualBasicDiagnosticFormatter.Instance.Format(iDiagnostic.WithLocation(Location.None)) diagnosticInfos.Add(ErrorFactory.ErrorInfo(ERRID.ERR_OverloadCandidate2, symbol, DirectCast(iDiagnostic, DiagnosticWithInfo).Info)) Next End If Else If isExtension Then diagnosticInfos.Add(ErrorFactory.ErrorInfo(ERRID.ERR_ExtensionMethodOverloadCandidate3, symbol, symbol.ContainingType, ErrorFactory.ErrorInfo(ERRID.ERR_DelegateBindingMismatch, symbol))) Else diagnosticInfos.Add(ErrorFactory.ErrorInfo(ERRID.ERR_OverloadCandidate2, symbol, ErrorFactory.ErrorInfo(ERRID.ERR_DelegateBindingMismatch, symbol))) End If End If Next Dim diagnosticCompoundInfos() As DiagnosticInfo = diagnosticInfos.ToArrayAndFree() If delegateSymbol Is Nothing Then ReportDiagnostic(diagnostics, diagnosticLocation, ErrorFactory.ErrorInfo(errorNo, CustomSymbolDisplayFormatter.ShortErrorName(candidates(0).Candidate.UnderlyingSymbol), New CompoundDiagnosticInfo(diagnosticCompoundInfos))) Else ReportDiagnostic(diagnostics, diagnosticLocation, ErrorFactory.ErrorInfo(errorNo, CustomSymbolDisplayFormatter.ShortErrorName(candidates(0).Candidate.UnderlyingSymbol), CustomSymbolDisplayFormatter.DelegateSignature(delegateSymbol), New CompoundDiagnosticInfo(diagnosticCompoundInfos))) End If End If diagnosticPerSymbol.Free() End Sub Private Shared Function ReportCommonErrorsFromLambdas( diagnosticPerSymbol As ArrayBuilder(Of KeyValuePair(Of Symbol, ReadOnlyBindingDiagnostic(Of AssemblySymbol))), arguments As ImmutableArray(Of BoundExpression), diagnostics As BindingDiagnosticBag ) As Boolean Dim haveCommonErrors As Boolean = False For Each diagnostic In diagnosticPerSymbol(0).Value.Diagnostics If diagnostic.Severity <> DiagnosticSeverity.Error Then Continue For End If For Each argument In arguments If argument.Syntax.SyntaxTree Is diagnostic.Location.SourceTree AndAlso argument.Kind = BoundKind.UnboundLambda Then If argument.Syntax.Span.Contains(diagnostic.Location.SourceSpan) Then Dim common As Boolean = True For i As Integer = 1 To diagnosticPerSymbol.Count - 1 If Not diagnosticPerSymbol(i).Value.Diagnostics.Contains(diagnostic) Then common = False Exit For End If Next If common Then haveCommonErrors = True diagnostics.Add(diagnostic) End If Exit For End If End If Next Next Return haveCommonErrors End Function ''' <summary> ''' Should be kept in sync with OverloadResolution.MatchArguments. Anything that ''' OverloadResolution.MatchArguments flags as an error should be detected by ''' this function as well. ''' </summary> Private Sub ReportOverloadResolutionFailureForASingleCandidate( node As SyntaxNode, diagnosticLocation As Location, lookupResult As LookupResultKind, ByRef candidateAnalysisResult As OverloadResolution.CandidateAnalysisResult, arguments As ImmutableArray(Of BoundExpression), argumentNames As ImmutableArray(Of String), allowUnexpandedParamArrayForm As Boolean, allowExpandedParamArrayForm As Boolean, includeMethodNameInErrorMessages As Boolean, reportNarrowingConversions As Boolean, diagnostics As BindingDiagnosticBag, delegateSymbol As Symbol, queryMode As Boolean, callerInfoOpt As SyntaxNode, representCandidateInDiagnosticsOpt As Symbol ) Dim candidate As OverloadResolution.Candidate = candidateAnalysisResult.Candidate If arguments.IsDefault Then arguments = ImmutableArray(Of BoundExpression).Empty End If Debug.Assert(argumentNames.IsDefaultOrEmpty OrElse (argumentNames.Length > 0 AndAlso argumentNames.Length = arguments.Length)) Debug.Assert(allowUnexpandedParamArrayForm OrElse allowExpandedParamArrayForm) If candidateAnalysisResult.State = VisualBasic.OverloadResolution.CandidateAnalysisResultState.HasUseSiteError OrElse candidateAnalysisResult.State = VisualBasic.OverloadResolution.CandidateAnalysisResultState.HasUnsupportedMetadata Then If lookupResult <> LookupResultKind.Inaccessible Then Debug.Assert(lookupResult = LookupResultKind.Good) ReportUseSite(diagnostics, diagnosticLocation, candidate.UnderlyingSymbol.GetUseSiteInfo()) End If Return End If ' To simplify following code If Not argumentNames.IsDefault AndAlso argumentNames.Length = 0 Then argumentNames = Nothing End If Dim parameterToArgumentMap As ArrayBuilder(Of Integer) = ArrayBuilder(Of Integer).GetInstance(candidate.ParameterCount, -1) Dim paramArrayItems As ArrayBuilder(Of Integer) = ArrayBuilder(Of Integer).GetInstance() Try '§11.8.2 Applicable Methods '1. First, match each positional argument in order to the list of method parameters. 'If there are more positional arguments than parameters and the last parameter is not a paramarray, the method is not applicable. 'Otherwise, the paramarray parameter is expanded with parameters of the paramarray element type to match the number of positional arguments. 'If a positional argument is omitted, the method is not applicable. ' !!! Not sure about the last sentence: "If a positional argument is omitted, the method is not applicable." ' !!! Dev10 allows omitting positional argument as long as the corresponding parameter is optional. Dim positionalArguments As Integer = 0 Dim paramIndex = 0 Dim someArgumentsBad As Boolean = False Dim someParamArrayArgumentsBad As Boolean = False Dim seenOutOfPositionNamedArgIndex As Integer = -1 Dim candidateSymbol As Symbol = candidate.UnderlyingSymbol Dim candidateIsExtension As Boolean = candidate.IsExtensionMethod For i As Integer = 0 To arguments.Length - 1 Step 1 ' A named argument which is used in-position counts as positional If Not argumentNames.IsDefault AndAlso argumentNames(i) IsNot Nothing Then If Not candidate.TryGetNamedParamIndex(argumentNames(i), paramIndex) Then Exit For End If If paramIndex <> i Then ' all remaining arguments must be named seenOutOfPositionNamedArgIndex = i Exit For End If If paramIndex = candidate.ParameterCount - 1 AndAlso candidate.Parameters(paramIndex).IsParamArray Then Exit For End If Debug.Assert(parameterToArgumentMap(paramIndex) = -1) End If If paramIndex = candidate.ParameterCount Then If Not someArgumentsBad Then If Not includeMethodNameInErrorMessages Then ReportDiagnostic(diagnostics, arguments(i).Syntax, ERRID.ERR_TooManyArgs) ElseIf candidateIsExtension Then ReportDiagnostic(diagnostics, arguments(i).Syntax, ERRID.ERR_TooManyArgs2, candidateSymbol, candidateSymbol.ContainingType) Else ReportDiagnostic(diagnostics, arguments(i).Syntax, ERRID.ERR_TooManyArgs1, If(representCandidateInDiagnosticsOpt, candidateSymbol)) End If someArgumentsBad = True End If ElseIf paramIndex = candidate.ParameterCount - 1 AndAlso candidate.Parameters(paramIndex).IsParamArray Then ' Collect ParamArray arguments While i < arguments.Length If Not argumentNames.IsDefault AndAlso argumentNames(i) IsNot Nothing Then ' First named argument Continue For End If If arguments(i).Kind = BoundKind.OmittedArgument Then ReportDiagnostic(diagnostics, arguments(i).Syntax, ERRID.ERR_OmittedParamArrayArgument) someParamArrayArgumentsBad = True Else paramArrayItems.Add(i) End If positionalArguments += 1 i += 1 End While Exit For Else parameterToArgumentMap(paramIndex) = i paramIndex += 1 End If positionalArguments += 1 Next Dim skippedSomeArguments As Boolean = False '§11.8.2 Applicable Methods '2. Next, match each named argument to a parameter with the given name. 'If one of the named arguments fails to match, matches a paramarray parameter, 'or matches an argument already matched with another positional or named argument, 'the method is not applicable. For i As Integer = positionalArguments To arguments.Length - 1 Step 1 Debug.Assert(argumentNames(i) Is Nothing OrElse argumentNames(i).Length > 0) If argumentNames(i) Is Nothing Then ' Unnamed argument follows out-of-position named arguments If Not someArgumentsBad Then ReportDiagnostic(diagnostics, GetNamedArgumentIdentifier(arguments(seenOutOfPositionNamedArgIndex).Syntax), ERRID.ERR_BadNonTrailingNamedArgument, argumentNames(seenOutOfPositionNamedArgIndex)) End If Return End If If Not candidate.TryGetNamedParamIndex(argumentNames(i), paramIndex) Then ' ERRID_NamedParamNotFound1 ' ERRID_NamedParamNotFound2 If Not includeMethodNameInErrorMessages Then ReportDiagnostic(diagnostics, GetNamedArgumentIdentifier(arguments(i).Syntax), ERRID.ERR_NamedParamNotFound1, argumentNames(i)) ElseIf candidateIsExtension Then ReportDiagnostic(diagnostics, GetNamedArgumentIdentifier(arguments(i).Syntax), ERRID.ERR_NamedParamNotFound3, argumentNames(i), candidateSymbol, candidateSymbol.ContainingType) Else ReportDiagnostic(diagnostics, GetNamedArgumentIdentifier(arguments(i).Syntax), ERRID.ERR_NamedParamNotFound2, argumentNames(i), If(representCandidateInDiagnosticsOpt, candidateSymbol)) End If someArgumentsBad = True Continue For End If If paramIndex = candidate.ParameterCount - 1 AndAlso candidate.Parameters(paramIndex).IsParamArray Then ' ERRID_NamedParamArrayArgument ReportDiagnostic(diagnostics, GetNamedArgumentIdentifier(arguments(i).Syntax), ERRID.ERR_NamedParamArrayArgument) someArgumentsBad = True Continue For End If If parameterToArgumentMap(paramIndex) <> -1 AndAlso arguments(parameterToArgumentMap(paramIndex)).Kind <> BoundKind.OmittedArgument Then ' ERRID_NamedArgUsedTwice1 ' ERRID_NamedArgUsedTwice2 ' ERRID_NamedArgUsedTwice3 If Not includeMethodNameInErrorMessages Then ReportDiagnostic(diagnostics, GetNamedArgumentIdentifier(arguments(i).Syntax), ERRID.ERR_NamedArgUsedTwice1, argumentNames(i)) ElseIf candidateIsExtension Then ReportDiagnostic(diagnostics, GetNamedArgumentIdentifier(arguments(i).Syntax), ERRID.ERR_NamedArgUsedTwice3, argumentNames(i), candidateSymbol, candidateSymbol.ContainingType) Else ReportDiagnostic(diagnostics, GetNamedArgumentIdentifier(arguments(i).Syntax), ERRID.ERR_NamedArgUsedTwice2, argumentNames(i), If(representCandidateInDiagnosticsOpt, candidateSymbol)) End If someArgumentsBad = True Continue For End If ' It is an error for a named argument to specify ' a value for an explicitly omitted positional argument. If paramIndex < positionalArguments Then 'ERRID_NamedArgAlsoOmitted1 'ERRID_NamedArgAlsoOmitted2 'ERRID_NamedArgAlsoOmitted3 If Not includeMethodNameInErrorMessages Then ReportDiagnostic(diagnostics, GetNamedArgumentIdentifier(arguments(i).Syntax), ERRID.ERR_NamedArgAlsoOmitted1, argumentNames(i)) ElseIf candidateIsExtension Then ReportDiagnostic(diagnostics, GetNamedArgumentIdentifier(arguments(i).Syntax), ERRID.ERR_NamedArgAlsoOmitted3, argumentNames(i), candidateSymbol, candidateSymbol.ContainingType) Else ReportDiagnostic(diagnostics, GetNamedArgumentIdentifier(arguments(i).Syntax), ERRID.ERR_NamedArgAlsoOmitted2, argumentNames(i), If(representCandidateInDiagnosticsOpt, candidateSymbol)) End If someArgumentsBad = True End If parameterToArgumentMap(paramIndex) = i Next ' Check whether type inference failed diagnostics.AddRange(candidateAnalysisResult.TypeArgumentInferenceDiagnosticsOpt) If candidate.IsGeneric AndAlso candidateAnalysisResult.State = OverloadResolution.CandidateAnalysisResultState.TypeInferenceFailed Then ' Bug 122092: AddressOf doesn't want detailed info on which parameters could not be ' inferred, just report the general type inference failed message in this case. If delegateSymbol IsNot Nothing Then ReportDiagnostic(diagnostics, diagnosticLocation, ERRID.ERR_DelegateBindingTypeInferenceFails) Return End If If Not candidateAnalysisResult.SomeInferenceFailed Then Dim reportedAnError As Boolean = False For i As Integer = 0 To candidate.Arity - 1 Step 1 If candidateAnalysisResult.NotInferredTypeArguments(i) Then If Not includeMethodNameInErrorMessages Then ReportDiagnostic(diagnostics, diagnosticLocation, ERRID.ERR_UnboundTypeParam1, candidate.TypeParameters(i)) ElseIf candidateIsExtension Then ReportDiagnostic(diagnostics, diagnosticLocation, ERRID.ERR_UnboundTypeParam3, candidate.TypeParameters(i), candidateSymbol, candidateSymbol.ContainingType) Else ReportDiagnostic(diagnostics, diagnosticLocation, ERRID.ERR_UnboundTypeParam2, candidate.TypeParameters(i), If(representCandidateInDiagnosticsOpt, candidateSymbol)) End If reportedAnError = True End If Next If reportedAnError Then Return End If End If Dim inferenceErrorReasons As InferenceErrorReasons = candidateAnalysisResult.InferenceErrorReasons If (inferenceErrorReasons And InferenceErrorReasons.Ambiguous) <> 0 Then If Not includeMethodNameInErrorMessages Then ReportDiagnostic(diagnostics, diagnosticLocation, If(queryMode, ERRID.ERR_TypeInferenceFailureNoExplicitAmbiguous1, ERRID.ERR_TypeInferenceFailureAmbiguous1)) ElseIf candidateIsExtension Then ReportDiagnostic(diagnostics, diagnosticLocation, If(queryMode, ERRID.ERR_TypeInferenceFailureNoExplicitAmbiguous3, ERRID.ERR_TypeInferenceFailureAmbiguous3), candidateSymbol, candidateSymbol.ContainingType) Else ReportDiagnostic(diagnostics, diagnosticLocation, If(queryMode, ERRID.ERR_TypeInferenceFailureNoExplicitAmbiguous2, ERRID.ERR_TypeInferenceFailureAmbiguous2), If(representCandidateInDiagnosticsOpt, candidateSymbol)) End If ElseIf (inferenceErrorReasons And InferenceErrorReasons.NoBest) <> 0 Then If Not includeMethodNameInErrorMessages Then ReportDiagnostic(diagnostics, diagnosticLocation, If(queryMode, ERRID.ERR_TypeInferenceFailureNoExplicitNoBest1, ERRID.ERR_TypeInferenceFailureNoBest1)) ElseIf candidateIsExtension Then ReportDiagnostic(diagnostics, diagnosticLocation, If(queryMode, ERRID.ERR_TypeInferenceFailureNoExplicitNoBest3, ERRID.ERR_TypeInferenceFailureNoBest3), candidateSymbol, candidateSymbol.ContainingType) Else ReportDiagnostic(diagnostics, diagnosticLocation, If(queryMode, ERRID.ERR_TypeInferenceFailureNoExplicitNoBest2, ERRID.ERR_TypeInferenceFailureNoBest2), If(representCandidateInDiagnosticsOpt, candidateSymbol)) End If Else If candidateAnalysisResult.TypeArgumentInferenceDiagnosticsOpt.HasAnyResolvedErrors Then ' Already reported some errors, let's not report a general inference error Return End If If Not includeMethodNameInErrorMessages Then ReportDiagnostic(diagnostics, diagnosticLocation, If(queryMode, ERRID.ERR_TypeInferenceFailureNoExplicit1, ERRID.ERR_TypeInferenceFailure1)) ElseIf candidateIsExtension Then ReportDiagnostic(diagnostics, diagnosticLocation, If(queryMode, ERRID.ERR_TypeInferenceFailureNoExplicit3, ERRID.ERR_TypeInferenceFailure3), candidateSymbol, candidateSymbol.ContainingType) Else ReportDiagnostic(diagnostics, diagnosticLocation, If(queryMode, ERRID.ERR_TypeInferenceFailureNoExplicit2, ERRID.ERR_TypeInferenceFailure2), If(representCandidateInDiagnosticsOpt, candidateSymbol)) End If End If Return End If ' Check generic constraints for method type arguments. If candidateAnalysisResult.State = OverloadResolution.CandidateAnalysisResultState.GenericConstraintsViolated Then Debug.Assert(candidate.IsGeneric) Debug.Assert(candidate.UnderlyingSymbol.Kind = SymbolKind.Method) Dim method = DirectCast(candidate.UnderlyingSymbol, MethodSymbol) ' TODO: Dev10 uses the location of the type parameter or argument that ' violated the constraint, rather than the entire invocation expression. Dim succeeded = method.CheckConstraints(Compilation.LanguageVersion, diagnosticLocation, diagnostics, template:=GetNewCompoundUseSiteInfo(diagnostics)) Debug.Assert(Not succeeded) Return End If If candidateAnalysisResult.TypeArgumentInferenceDiagnosticsOpt.HasAnyErrors Then Return End If ' Traverse the parameters, converting corresponding arguments ' as appropriate. Dim argIndex As Integer Dim candidateIsAProperty As Boolean = (candidateSymbol.Kind = SymbolKind.Property) For paramIndex = 0 To candidate.ParameterCount - 1 Step 1 Dim param As ParameterSymbol = candidate.Parameters(paramIndex) Dim isByRef As Boolean = param.IsByRef Dim targetType As TypeSymbol = param.Type Dim argument As BoundExpression = Nothing If param.IsParamArray AndAlso paramIndex = candidate.ParameterCount - 1 Then If targetType.Kind <> SymbolKind.ArrayType Then If targetType.Kind <> SymbolKind.ErrorType Then ' ERRID_ParamArrayWrongType ReportDiagnostic(diagnostics, diagnosticLocation, ERRID.ERR_ParamArrayWrongType) End If someArgumentsBad = True Continue For ElseIf someParamArrayArgumentsBad Then Continue For End If If paramArrayItems.Count = 1 Then Dim paramArrayArgument = arguments(paramArrayItems(0)) '§11.8.2 Applicable Methods 'If the conversion from the type of the argument expression to the paramarray type is narrowing, 'then the method is only applicable in its expanded form. Dim arrayConversion As KeyValuePair(Of ConversionKind, MethodSymbol) = Nothing If allowUnexpandedParamArrayForm AndAlso Not (Not paramArrayArgument.HasErrors AndAlso OverloadResolution.CanPassToParamArray(paramArrayArgument, targetType, arrayConversion, Me, CompoundUseSiteInfo(Of AssemblySymbol).Discarded)) Then allowUnexpandedParamArrayForm = False End If '§11.8.2 Applicable Methods 'If the argument expression is the literal Nothing, then the method is only applicable in its unexpanded form If allowExpandedParamArrayForm AndAlso paramArrayArgument.IsNothingLiteral() Then allowExpandedParamArrayForm = False End If Else ' Unexpanded form is not applicable: there are either more than one value or no values. If Not allowExpandedParamArrayForm Then If paramArrayItems.Count = 0 Then If Not includeMethodNameInErrorMessages Then ReportDiagnostic(diagnostics, diagnosticLocation, ERRID.ERR_OmittedArgument1, CustomSymbolDisplayFormatter.ShortErrorName(param)) ElseIf candidateIsExtension Then ReportDiagnostic(diagnostics, diagnosticLocation, ERRID.ERR_OmittedArgument3, CustomSymbolDisplayFormatter.ShortErrorName(param), candidateSymbol, candidateSymbol.ContainingType) Else ReportDiagnostic(diagnostics, diagnosticLocation, ERRID.ERR_OmittedArgument2, CustomSymbolDisplayFormatter.ShortErrorName(param), If(representCandidateInDiagnosticsOpt, candidateSymbol)) End If Else If Not includeMethodNameInErrorMessages Then ReportDiagnostic(diagnostics, diagnosticLocation, ERRID.ERR_TooManyArgs) ElseIf candidateIsExtension Then ReportDiagnostic(diagnostics, diagnosticLocation, ERRID.ERR_TooManyArgs2, candidateSymbol, candidateSymbol.ContainingType) Else ReportDiagnostic(diagnostics, diagnosticLocation, ERRID.ERR_TooManyArgs1, If(representCandidateInDiagnosticsOpt, candidateSymbol)) End If End If someArgumentsBad = True Continue For End If allowUnexpandedParamArrayForm = False End If If allowUnexpandedParamArrayForm Then argument = arguments(paramArrayItems(0)) ReportByValConversionErrors(param, argument, targetType, reportNarrowingConversions, diagnostics) ElseIf allowExpandedParamArrayForm Then Dim arrayType = DirectCast(targetType, ArrayTypeSymbol) If Not arrayType.IsSZArray Then ' ERRID_ParamArrayWrongType ReportDiagnostic(diagnostics, diagnosticLocation, ERRID.ERR_ParamArrayWrongType) someArgumentsBad = True Continue For End If Dim arrayElementType = arrayType.ElementType For i As Integer = 0 To paramArrayItems.Count - 1 Step 1 argument = arguments(paramArrayItems(i)) ReportByValConversionErrors(param, argument, arrayElementType, reportNarrowingConversions, diagnostics) Next Else Debug.Assert(paramArrayItems.Count = 1) Dim paramArrayArgument = arguments(paramArrayItems(0)) ReportDiagnostic(diagnostics, paramArrayArgument.Syntax, ERRID.ERR_ParamArrayArgumentMismatch) End If Continue For End If argIndex = parameterToArgumentMap(paramIndex) argument = If(argIndex = -1, Nothing, arguments(argIndex)) ' Argument nothing when the argument syntax is missing or BoundKind.OmittedArgument when the argument list contains commas ' for the missing syntax so we have to test for both. If argument Is Nothing OrElse argument.Kind = BoundKind.OmittedArgument Then If argument Is Nothing AndAlso skippedSomeArguments Then someArgumentsBad = True Continue For End If 'See Section 3 of §11.8.2 Applicable Methods ' Deal with Optional arguments ' Need to handle optional arguments here, there could be conversion errors, etc. ' reducedExtensionReceiverOpt is used to determine the default value of a CallerArgumentExpression when it refers to the first parameter of an extension method. ' Don't bother with correctly determining the correct value for this case since we're in an error case anyway. argument = GetArgumentForParameterDefaultValue(param, node, diagnostics, callerInfoOpt, parameterToArgumentMap, arguments, reducedExtensionReceiverOpt:=Nothing) If argument Is Nothing Then If Not includeMethodNameInErrorMessages Then ReportDiagnostic(diagnostics, diagnosticLocation, ERRID.ERR_OmittedArgument1, CustomSymbolDisplayFormatter.ShortErrorName(param)) ElseIf candidateIsExtension Then ReportDiagnostic(diagnostics, diagnosticLocation, ERRID.ERR_OmittedArgument3, CustomSymbolDisplayFormatter.ShortErrorName(param), candidateSymbol, candidateSymbol.ContainingType) Else ReportDiagnostic(diagnostics, diagnosticLocation, ERRID.ERR_OmittedArgument2, CustomSymbolDisplayFormatter.ShortErrorName(param), If(representCandidateInDiagnosticsOpt, candidateSymbol)) End If someArgumentsBad = True Continue For End If End If Debug.Assert(Not isByRef OrElse param.IsExplicitByRef OrElse targetType.IsStringType()) ' Arguments for properties are always passed with ByVal semantics. Even if ' parameter in metadata is defined ByRef, we always pass corresponding argument ' through a temp without copy-back. Unlike with method calls, we rely on CodeGen ' to introduce the temp (easy to do since there is no copy-back around it), ' this allows us to keep the BoundPropertyAccess node simpler and allows to avoid ' A LOT of complexity in UseTwiceRewriter, which we would otherwise have around ' the temps. ' Non-string arguments for implicitly ByRef string parameters of Declare functions ' are passed through a temp without copy-back. If isByRef AndAlso Not candidateIsAProperty AndAlso (param.IsExplicitByRef OrElse (argument.Type IsNot Nothing AndAlso argument.Type.IsStringType())) Then ReportByRefConversionErrors(candidate, param, argument, targetType, reportNarrowingConversions, diagnostics, diagnosticNode:=node, delegateSymbol:=delegateSymbol) Else ReportByValConversionErrors(param, argument, targetType, reportNarrowingConversions, diagnostics, diagnosticNode:=node, delegateSymbol:=delegateSymbol) End If Next Finally paramArrayItems.Free() parameterToArgumentMap.Free() End Try End Sub ''' <summary> ''' Should be in sync with OverloadResolution.MatchArgumentToByRefParameter ''' </summary> Private Sub ReportByRefConversionErrors( candidate As OverloadResolution.Candidate, param As ParameterSymbol, argument As BoundExpression, targetType As TypeSymbol, reportNarrowingConversions As Boolean, diagnostics As BindingDiagnosticBag, Optional diagnosticNode As SyntaxNode = Nothing, Optional delegateSymbol As Symbol = Nothing ) ' TODO: Do we need to do more thorough check for error types here, i.e. dig into generics, ' arrays, etc., detect types from unreferenced assemblies, ... ? If targetType.IsErrorType() OrElse argument.HasErrors Then ' UNDONE: should HasErrors really always cause argument mismatch [petergo, 3/9/2011] Return End If If argument.IsSupportingAssignment() Then If Not (argument.IsLValue() AndAlso targetType.IsSameTypeIgnoringAll(argument.Type)) Then If Not ReportByValConversionErrors(param, argument, targetType, reportNarrowingConversions, diagnostics, diagnosticNode:=diagnosticNode, delegateSymbol:=delegateSymbol) Then ' Check copy back conversion Dim boundTemp = New BoundRValuePlaceholder(argument.Syntax, targetType) Dim copyBackType = argument.GetTypeOfAssignmentTarget() Dim conv As KeyValuePair(Of ConversionKind, MethodSymbol) = Conversions.ClassifyConversion(boundTemp, copyBackType, Me, CompoundUseSiteInfo(Of AssemblySymbol).Discarded) If Conversions.NoConversion(conv.Key) Then ' Possible only with user-defined conversions, I think. CreateConversionAndReportDiagnostic(argument.Syntax, boundTemp, conv, False, copyBackType, diagnostics, copybackConversionParamName:=param.Name) ElseIf Conversions.IsNarrowingConversion(conv.Key) Then Debug.Assert((conv.Key And ConversionKind.InvolvesNarrowingFromNumericConstant) = 0) If OptionStrict = VisualBasic.OptionStrict.On Then CreateConversionAndReportDiagnostic(argument.Syntax, boundTemp, conv, False, copyBackType, diagnostics, copybackConversionParamName:=param.Name) ElseIf reportNarrowingConversions Then ReportDiagnostic(diagnostics, argument.Syntax, ERRID.ERR_ArgumentCopyBackNarrowing3, CustomSymbolDisplayFormatter.ShortErrorName(param), targetType, copyBackType) End If End If End If End If Else ' No copy back needed ' If we are inside a lambda in a constructor and are passing ByRef a non-LValue field, which ' would be an LValue field, if it were referred to in the constructor outside of a lambda, ' we need to report an error because the operation will result in a simulated pass by ' ref (through a temp, without a copy back), which might be not the intent. If Report_ERRID_ReadOnlyInClosure(argument) Then ReportDiagnostic(diagnostics, argument.Syntax, ERRID.ERR_ReadOnlyInClosure) End If ReportByValConversionErrors(param, argument, targetType, reportNarrowingConversions, diagnostics, diagnosticNode:=diagnosticNode, delegateSymbol:=delegateSymbol) End If End Sub ''' <summary> ''' Should be in sync with OverloadResolution.MatchArgumentToByValParameter. ''' </summary> Private Function ReportByValConversionErrors( param As ParameterSymbol, argument As BoundExpression, targetType As TypeSymbol, reportNarrowingConversions As Boolean, diagnostics As BindingDiagnosticBag, Optional diagnosticNode As SyntaxNode = Nothing, Optional delegateSymbol As Symbol = Nothing ) As Boolean ' TODO: Do we need to do more thorough check for error types here, i.e. dig into generics, ' arrays, etc., detect types from unreferenced assemblies, ... ? If targetType.IsErrorType() OrElse argument.HasErrors Then ' UNDONE: should HasErrors really always cause argument mismatch [petergo, 3/9/2011] Return True End If Dim conv As KeyValuePair(Of ConversionKind, MethodSymbol) = Conversions.ClassifyConversion(argument, targetType, Me, CompoundUseSiteInfo(Of AssemblySymbol).Discarded) If Conversions.NoConversion(conv.Key) Then If delegateSymbol Is Nothing Then CreateConversionAndReportDiagnostic(argument.Syntax, argument, conv, False, targetType, diagnostics) Else ' in case of delegates, use the operand of the AddressOf as location for this error CreateConversionAndReportDiagnostic(diagnosticNode, argument, conv, False, targetType, diagnostics) End If Return True End If Dim requiresNarrowingConversion As Boolean = False If Conversions.IsNarrowingConversion(conv.Key) Then If (conv.Key And ConversionKind.InvolvesNarrowingFromNumericConstant) = 0 Then If OptionStrict = VisualBasic.OptionStrict.On Then If delegateSymbol Is Nothing Then CreateConversionAndReportDiagnostic(argument.Syntax, argument, conv, False, targetType, diagnostics) Else ' in case of delegates, use the operand of the AddressOf as location for this error ' because delegates have different error messages in case there is one or more candidates for narrowing ' indicate this as well. CreateConversionAndReportDiagnostic(diagnosticNode, argument, conv, False, targetType, diagnostics) End If Return True End If End If requiresNarrowingConversion = True ElseIf (conv.Key And ConversionKind.InvolvesNarrowingFromNumericConstant) <> 0 Then ' Dev10 overload resolution treats conversions that involve narrowing from numeric constant type ' as narrowing. requiresNarrowingConversion = True End If If reportNarrowingConversions AndAlso requiresNarrowingConversion Then Dim err As ERRID = ERRID.ERR_ArgumentNarrowing3 Dim targetDelegateType = targetType.DelegateOrExpressionDelegate(Me) If argument.Kind = BoundKind.QueryLambda AndAlso targetDelegateType IsNot Nothing Then Dim invoke As MethodSymbol = targetDelegateType.DelegateInvokeMethod If invoke IsNot Nothing AndAlso Not invoke.IsSub Then err = ERRID.ERR_NestedFunctionArgumentNarrowing3 argument = DirectCast(argument, BoundQueryLambda).Expression targetType = invoke.ReturnType End If End If If argument.Type Is Nothing Then ReportDiagnostic(diagnostics, argument.Syntax, ERRID.ERR_ArgumentNarrowing2, CustomSymbolDisplayFormatter.ShortErrorName(param), targetType) Else ReportDiagnostic(diagnostics, argument.Syntax, err, CustomSymbolDisplayFormatter.ShortErrorName(param), argument.Type, targetType) End If End If Return False End Function ''' <summary> ''' Should be kept in sync with OverloadResolution.MatchArguments, which populates ''' data this function operates on. ''' </summary> Private Function PassArguments( node As SyntaxNode, ByRef candidate As OverloadResolution.CandidateAnalysisResult, arguments As ImmutableArray(Of BoundExpression), diagnostics As BindingDiagnosticBag ) As (Arguments As ImmutableArray(Of BoundExpression), DefaultArguments As BitVector) Debug.Assert(candidate.State = OverloadResolution.CandidateAnalysisResultState.Applicable) If (arguments.IsDefault) Then arguments = ImmutableArray(Of BoundExpression).Empty End If Dim paramCount As Integer = candidate.Candidate.ParameterCount Dim parameterToArgumentMap = ArrayBuilder(Of Integer).GetInstance(paramCount, -1) Dim argumentsInOrder = ArrayBuilder(Of BoundExpression).GetInstance(paramCount) Dim defaultArguments = BitVector.Null Dim paramArrayItems As ArrayBuilder(Of Integer) = Nothing If candidate.IsExpandedParamArrayForm Then paramArrayItems = ArrayBuilder(Of Integer).GetInstance() End If Dim paramIndex As Integer ' For each parameter figure out matching argument. If candidate.ArgsToParamsOpt.IsDefaultOrEmpty Then Dim regularParamCount As Integer = paramCount If candidate.IsExpandedParamArrayForm Then regularParamCount -= 1 End If For i As Integer = 0 To Math.Min(regularParamCount, arguments.Length) - 1 Step 1 If arguments(i).Kind <> BoundKind.OmittedArgument Then parameterToArgumentMap(i) = i End If Next If candidate.IsExpandedParamArrayForm Then For i As Integer = regularParamCount To arguments.Length - 1 Step 1 paramArrayItems.Add(i) Next End If Else Dim argsToParams = candidate.ArgsToParamsOpt For i As Integer = 0 To argsToParams.Length - 1 Step 1 paramIndex = argsToParams(i) If arguments(i).Kind <> BoundKind.OmittedArgument Then If (candidate.IsExpandedParamArrayForm AndAlso paramIndex = candidate.Candidate.ParameterCount - 1) Then paramArrayItems.Add(i) Else parameterToArgumentMap(paramIndex) = i End If End If Next End If ' Traverse the parameters, converting corresponding arguments ' as appropriate. Dim candidateIsAProperty As Boolean = (candidate.Candidate.UnderlyingSymbol.Kind = SymbolKind.Property) For paramIndex = 0 To paramCount - 1 Step 1 Dim param As ParameterSymbol = candidate.Candidate.Parameters(paramIndex) Dim targetType As TypeSymbol = param.Type Dim argument As BoundExpression = Nothing Dim conversion As KeyValuePair(Of ConversionKind, MethodSymbol) = Conversions.Identity Dim conversionBack As KeyValuePair(Of ConversionKind, MethodSymbol) = Conversions.Identity If candidate.IsExpandedParamArrayForm AndAlso paramIndex = candidate.Candidate.ParameterCount - 1 Then Dim arrayElementType = DirectCast(targetType, ArrayTypeSymbol).ElementType Dim items = ArrayBuilder(Of BoundExpression).GetInstance(paramArrayItems.Count) For i As Integer = 0 To paramArrayItems.Count - 1 Step 1 items.Add(PassArgumentByVal(arguments(paramArrayItems(i)), If(candidate.ConversionsOpt.IsDefaultOrEmpty, Conversions.Identity, candidate.ConversionsOpt(paramArrayItems(i))), arrayElementType, diagnostics)) Next ' Create the bound array and ensure that it is marked as compiler generated. argument = New BoundArrayCreation(node, True, (New BoundExpression() {New BoundLiteral(node, ConstantValue.Create(items.Count), GetSpecialType(SpecialType.System_Int32, node, diagnostics)).MakeCompilerGenerated()}).AsImmutableOrNull(), New BoundArrayInitialization(node, items.ToImmutableAndFree(), targetType).MakeCompilerGenerated(), Nothing, Nothing, targetType).MakeCompilerGenerated() Else Dim argIndex As Integer argIndex = parameterToArgumentMap(paramIndex) argument = If(argIndex = -1, Nothing, arguments(argIndex)) If argument IsNot Nothing AndAlso paramIndex = candidate.Candidate.ParameterCount - 1 AndAlso param.IsParamArray Then argument = ApplyImplicitConversion(argument.Syntax, targetType, argument, diagnostics) ' Leave both conversions at identity since we already applied the conversion ElseIf argIndex > -1 Then If Not candidate.ConversionsOpt.IsDefaultOrEmpty Then conversion = candidate.ConversionsOpt(argIndex) End If If Not candidate.ConversionsBackOpt.IsDefaultOrEmpty Then conversionBack = candidate.ConversionsBackOpt(argIndex) End If End If End If Dim argumentIsDefaultValue As Boolean = False If argument Is Nothing Then Debug.Assert(Not candidate.OptionalArguments.IsEmpty, "Optional arguments expected") If defaultArguments.IsNull Then defaultArguments = BitVector.Create(paramCount) End If ' Deal with Optional arguments Dim defaultArgument As OverloadResolution.OptionalArgument = candidate.OptionalArguments(paramIndex) argument = defaultArgument.DefaultValue diagnostics.AddDependencies(defaultArgument.Dependencies) argumentIsDefaultValue = True defaultArguments(paramIndex) = True Debug.Assert(argument IsNot Nothing) conversion = defaultArgument.Conversion Dim argType = argument.Type If argType IsNot Nothing Then ' Report usesiteerror if it exists. Dim useSiteInfo = argType.GetUseSiteInfo ReportUseSite(diagnostics, argument.Syntax, useSiteInfo) End If End If ' Arguments for properties are always passed with ByVal semantics. Even if ' parameter in metadata is defined ByRef, we always pass corresponding argument ' through a temp without copy-back. Unlike with method calls, we rely on CodeGen ' to introduce the temp (easy to do since there is no copy-back around it), ' this allows us to keep the BoundPropertyAccess node simpler and allows to avoid ' A LOT of complexity in UseTwiceRewriter, which we would otherwise have around ' the temps. Debug.Assert(Not argumentIsDefaultValue OrElse argument.WasCompilerGenerated) Dim adjustedArgument As BoundExpression = PassArgument(argument, conversion, candidateIsAProperty, conversionBack, targetType, param, diagnostics) ' Keep SemanticModel happy. If argumentIsDefaultValue AndAlso adjustedArgument IsNot argument Then adjustedArgument.SetWasCompilerGenerated() End If argumentsInOrder.Add(adjustedArgument) Next If paramArrayItems IsNot Nothing Then paramArrayItems.Free() End If parameterToArgumentMap.Free() Return (argumentsInOrder.ToImmutableAndFree(), defaultArguments) End Function Private Function PassArgument( argument As BoundExpression, conversionTo As KeyValuePair(Of ConversionKind, MethodSymbol), forceByValueSemantics As Boolean, conversionFrom As KeyValuePair(Of ConversionKind, MethodSymbol), targetType As TypeSymbol, param As ParameterSymbol, diagnostics As BindingDiagnosticBag ) As BoundExpression Debug.Assert(Not param.IsByRef OrElse param.IsExplicitByRef OrElse targetType.IsStringType()) ' Non-string arguments for implicitly ByRef string parameters of Declare functions ' are passed through a temp without copy-back. If param.IsByRef AndAlso Not forceByValueSemantics AndAlso (param.IsExplicitByRef OrElse (argument.Type IsNot Nothing AndAlso argument.Type.IsStringType())) Then Return PassArgumentByRef(param.IsOut, argument, conversionTo, conversionFrom, targetType, param.Name, diagnostics) Else Return PassArgumentByVal(argument, conversionTo, targetType, diagnostics) End If End Function Private Function PassArgumentByRef( isOutParameter As Boolean, argument As BoundExpression, conversionTo As KeyValuePair(Of ConversionKind, MethodSymbol), conversionFrom As KeyValuePair(Of ConversionKind, MethodSymbol), targetType As TypeSymbol, parameterName As String, diagnostics As BindingDiagnosticBag ) As BoundExpression #If DEBUG Then Dim checkAgainst As KeyValuePair(Of ConversionKind, MethodSymbol) = Conversions.ClassifyConversion(argument, targetType, Me, CompoundUseSiteInfo(Of AssemblySymbol).Discarded) Debug.Assert(conversionTo.Key = checkAgainst.Key) Debug.Assert(Equals(conversionTo.Value, checkAgainst.Value)) #End If ' TODO: Fields of MarshalByRef object are passed via temp. Dim isLValue As Boolean = argument.IsLValue() If isLValue AndAlso argument.Kind = BoundKind.PropertyAccess Then argument = argument.SetAccessKind(PropertyAccessKind.Get) End If If isLValue AndAlso Conversions.IsIdentityConversion(conversionTo.Key) Then 'Nothing to do Debug.Assert(Conversions.IsIdentityConversion(conversionFrom.Key)) Return argument ElseIf isLValue OrElse argument.IsSupportingAssignment() Then ' Need to allocate a temp of the target type, ' init it with argument's value, ' pass it ByRef, ' copy value back after the call. Dim inPlaceholder = New BoundByRefArgumentPlaceholder(argument.Syntax, isOutParameter, argument.Type, argument.HasErrors).MakeCompilerGenerated() Dim inConversion = CreateConversionAndReportDiagnostic(argument.Syntax, inPlaceholder, conversionTo, False, targetType, diagnostics) Dim outPlaceholder = New BoundRValuePlaceholder(argument.Syntax, targetType).MakeCompilerGenerated() Dim copyBackType = argument.GetTypeOfAssignmentTarget() #If DEBUG Then checkAgainst = Conversions.ClassifyConversion(outPlaceholder, copyBackType, Me, CompoundUseSiteInfo(Of AssemblySymbol).Discarded) Debug.Assert(conversionFrom.Key = checkAgainst.Key) Debug.Assert(Equals(conversionFrom.Value, checkAgainst.Value)) #End If Dim outConversion = CreateConversionAndReportDiagnostic(argument.Syntax, outPlaceholder, conversionFrom, False, copyBackType, diagnostics, copybackConversionParamName:=parameterName).MakeCompilerGenerated() ' since we are going to assign to a latebound invocation ' force its arguments to be rvalues. If argument.Kind = BoundKind.LateInvocation Then argument = MakeArgsRValues(DirectCast(argument, BoundLateInvocation), diagnostics) End If Dim copyBackExpression = BindAssignment(argument.Syntax, argument, outConversion, diagnostics) Debug.Assert(copyBackExpression.HasErrors OrElse (copyBackExpression.Kind = BoundKind.AssignmentOperator AndAlso DirectCast(copyBackExpression, BoundAssignmentOperator).Right Is outConversion)) If Not isLValue Then If argument.IsLateBound() Then argument = argument.SetLateBoundAccessKind(LateBoundAccessKind.Get Or LateBoundAccessKind.Set) Else ' Diagnostics for PropertyAccessKind.Set case has been reported when we called BindAssignment. WarnOnRecursiveAccess(argument, PropertyAccessKind.Get, diagnostics) argument = argument.SetAccessKind(PropertyAccessKind.Get Or PropertyAccessKind.Set) End If End If Return New BoundByRefArgumentWithCopyBack(argument.Syntax, argument, inConversion, inPlaceholder, outConversion, outPlaceholder, targetType, copyBackExpression.HasErrors).MakeCompilerGenerated() Else Dim propertyAccess = TryCast(argument, BoundPropertyAccess) If propertyAccess IsNot Nothing AndAlso propertyAccess.AccessKind <> PropertyAccessKind.Get AndAlso propertyAccess.PropertySymbol.SetMethod?.IsInitOnly Then Debug.Assert(Not propertyAccess.IsWriteable) ' Used to be writable prior to VB 16.9, which caused a use-site error while binding an assignment above. InternalSyntax.Parser.CheckFeatureAvailability(diagnostics, argument.Syntax.Location, DirectCast(argument.Syntax.SyntaxTree.Options, VisualBasicParseOptions).LanguageVersion, InternalSyntax.Feature.InitOnlySettersUsage) End If ' Need to allocate a temp of the target type, ' init it with argument's value, ' pass it ByRef. Code gen will do this. Return PassArgumentByVal(argument, conversionTo, targetType, diagnostics) End If End Function ' when latebound invocation acts as an LHS in an assignment ' its arguments are always passed ByVal since property parameters ' are always treated as ByVal ' This method is used to force the arguments to be RValues Private Function MakeArgsRValues(ByVal invocation As BoundLateInvocation, diagnostics As BindingDiagnosticBag) As BoundLateInvocation Dim args = invocation.ArgumentsOpt If Not args.IsEmpty Then Dim argBuilder As ArrayBuilder(Of BoundExpression) = Nothing For i As Integer = 0 To args.Length - 1 Dim arg = args(i) Dim newArg = MakeRValue(arg, diagnostics) If argBuilder Is Nothing AndAlso arg IsNot newArg Then argBuilder = ArrayBuilder(Of BoundExpression).GetInstance argBuilder.AddRange(args, i) End If If argBuilder IsNot Nothing Then argBuilder.Add(newArg) End If Next If argBuilder IsNot Nothing Then invocation = invocation.Update(invocation.Member, argBuilder.ToImmutableAndFree, invocation.ArgumentNamesOpt, invocation.AccessKind, invocation.MethodOrPropertyGroupOpt, invocation.Type) End If End If Return invocation End Function Friend Function PassArgumentByVal( argument As BoundExpression, conversion As KeyValuePair(Of ConversionKind, MethodSymbol), targetType As TypeSymbol, diagnostics As BindingDiagnosticBag ) As BoundExpression #If DEBUG Then Dim checkAgainst As KeyValuePair(Of ConversionKind, MethodSymbol) = Conversions.ClassifyConversion(argument, targetType, Me, CompoundUseSiteInfo(Of AssemblySymbol).Discarded) Debug.Assert(conversion.Key = checkAgainst.Key) Debug.Assert(Equals(conversion.Value, checkAgainst.Value)) #End If argument = CreateConversionAndReportDiagnostic(argument.Syntax, argument, conversion, False, targetType, diagnostics) Debug.Assert(Not argument.IsLValue) Return argument End Function ' Given a list of arguments, create arrays of the bound arguments and the names of those arguments. Private Sub BindArgumentsAndNames( argumentListOpt As ArgumentListSyntax, ByRef boundArguments As ImmutableArray(Of BoundExpression), ByRef argumentNames As ImmutableArray(Of String), ByRef argumentNamesLocations As ImmutableArray(Of Location), diagnostics As BindingDiagnosticBag ) Dim args As ImmutableArray(Of ArgumentSyntax) = Nothing If argumentListOpt IsNot Nothing Then Dim arguments = argumentListOpt.Arguments Dim argsArr(arguments.Count - 1) As ArgumentSyntax For i = 0 To argsArr.Length - 1 argsArr(i) = arguments(i) Next args = argsArr.AsImmutableOrNull End If BindArgumentsAndNames( args, boundArguments, argumentNames, argumentNamesLocations, diagnostics ) End Sub ' Given a list of arguments, create arrays of the bound arguments and the names of those arguments. Private Sub BindArgumentsAndNames( arguments As ImmutableArray(Of ArgumentSyntax), ByRef boundArguments As ImmutableArray(Of BoundExpression), ByRef argumentNames As ImmutableArray(Of String), ByRef argumentNamesLocations As ImmutableArray(Of Location), diagnostics As BindingDiagnosticBag ) ' With SeparatedSyntaxList, it is most efficient to iterate with foreach and not to access Count. If arguments.IsDefaultOrEmpty Then boundArguments = s_noArguments argumentNames = Nothing argumentNamesLocations = Nothing Else Dim boundArgumentsBuilder As ArrayBuilder(Of BoundExpression) = ArrayBuilder(Of BoundExpression).GetInstance Dim argumentNamesBuilder As ArrayBuilder(Of String) = Nothing Dim argumentNamesLocationsBuilder As ArrayBuilder(Of Location) = Nothing Dim argCount As Integer = 0 Dim argumentSyntax As ArgumentSyntax For Each argumentSyntax In arguments Select Case argumentSyntax.Kind Case SyntaxKind.SimpleArgument Dim simpleArgument = DirectCast(argumentSyntax, SimpleArgumentSyntax) boundArgumentsBuilder.Add(BindValue(simpleArgument.Expression, diagnostics)) If simpleArgument.IsNamed Then ' The common case is no named arguments. So we defer all work until the first named argument is seen. If argumentNamesBuilder Is Nothing Then argumentNamesBuilder = ArrayBuilder(Of String).GetInstance() argumentNamesLocationsBuilder = ArrayBuilder(Of Location).GetInstance() For i = 0 To argCount - 1 argumentNamesBuilder.Add(Nothing) argumentNamesLocationsBuilder.Add(Nothing) Next i End If Dim id = simpleArgument.NameColonEquals.Name.Identifier If id.ValueText.Length > 0 Then argumentNamesBuilder.Add(id.ValueText) Else argumentNamesBuilder.Add(Nothing) End If argumentNamesLocationsBuilder.Add(id.GetLocation()) ElseIf argumentNamesBuilder IsNot Nothing Then argumentNamesBuilder.Add(Nothing) argumentNamesLocationsBuilder.Add(Nothing) End If Case SyntaxKind.OmittedArgument boundArgumentsBuilder.Add(New BoundOmittedArgument(argumentSyntax, Nothing)) If argumentNamesBuilder IsNot Nothing Then argumentNamesBuilder.Add(Nothing) argumentNamesLocationsBuilder.Add(Nothing) End If Case SyntaxKind.RangeArgument ' NOTE: Redim statement supports range argument, like: Redim x(0 To 3)(0 To 6) ' This behavior is misleading, because the 'range' (0 To 3) is actually ' being ignored and only upper bound is being used. ' TODO: revise (add warning/error?) Dim rangeArgument = DirectCast(argumentSyntax, RangeArgumentSyntax) CheckRangeArgumentLowerBound(rangeArgument, diagnostics) boundArgumentsBuilder.Add(BindValue(rangeArgument.UpperBound, diagnostics)) If argumentNamesBuilder IsNot Nothing Then argumentNamesBuilder.Add(Nothing) argumentNamesLocationsBuilder.Add(Nothing) End If Case Else Throw ExceptionUtilities.UnexpectedValue(argumentSyntax.Kind) End Select argCount += 1 Next boundArguments = boundArgumentsBuilder.ToImmutableAndFree argumentNames = If(argumentNamesBuilder Is Nothing, Nothing, argumentNamesBuilder.ToImmutableAndFree) argumentNamesLocations = If(argumentNamesLocationsBuilder Is Nothing, Nothing, argumentNamesLocationsBuilder.ToImmutableAndFree) End If End Sub Friend Function GetArgumentForParameterDefaultValue(param As ParameterSymbol, syntax As SyntaxNode, diagnostics As BindingDiagnosticBag, callerInfoOpt As SyntaxNode, parameterToArgumentMap As ArrayBuilder(Of Integer), arguments As ImmutableArray(Of BoundExpression), reducedExtensionReceiverOpt As BoundExpression) As BoundExpression Dim defaultArgument As BoundExpression = Nothing ' See Section 3 of §11.8.2 Applicable Methods ' Deal with Optional arguments. HasDefaultValue is true if the parameter is optional and has a default value. Dim defaultConstantValue As ConstantValue = If(param.IsOptional, param.ExplicitDefaultConstantValue(DefaultParametersInProgress), Nothing) If defaultConstantValue IsNot Nothing Then If callerInfoOpt IsNot Nothing AndAlso callerInfoOpt.SyntaxTree IsNot Nothing AndAlso Not callerInfoOpt.SyntaxTree.IsEmbeddedOrMyTemplateTree() AndAlso Not SuppressCallerInfo Then Dim isCallerLineNumber As Boolean = param.IsCallerLineNumber Dim isCallerMemberName As Boolean = param.IsCallerMemberName Dim isCallerFilePath As Boolean = param.IsCallerFilePath Dim callerArgumentExpressionParameterIndex As Integer = param.CallerArgumentExpressionParameterIndex Dim isCallerArgumentExpression = callerArgumentExpressionParameterIndex > -1 OrElse (reducedExtensionReceiverOpt IsNot Nothing AndAlso callerArgumentExpressionParameterIndex > -2) If isCallerLineNumber OrElse isCallerMemberName OrElse isCallerFilePath OrElse isCallerArgumentExpression Then Dim callerInfoValue As ConstantValue = Nothing If isCallerLineNumber Then callerInfoValue = ConstantValue.Create(callerInfoOpt.SyntaxTree.GetDisplayLineNumber(GetCallerLocation(callerInfoOpt))) ElseIf isCallerMemberName Then Dim container As Symbol = ContainingMember While container IsNot Nothing Select Case container.Kind Case SymbolKind.Field, SymbolKind.Property, SymbolKind.Event Exit While Case SymbolKind.Method If container.IsLambdaMethod Then container = container.ContainingSymbol Else Dim propertyOrEvent As Symbol = DirectCast(container, MethodSymbol).AssociatedSymbol If propertyOrEvent IsNot Nothing Then container = propertyOrEvent End If Exit While End If Case Else container = container.ContainingSymbol End Select End While If container IsNot Nothing AndAlso container.Name IsNot Nothing Then callerInfoValue = ConstantValue.Create(container.Name) End If ElseIf isCallerFilePath Then callerInfoValue = ConstantValue.Create(callerInfoOpt.SyntaxTree.GetDisplayPath(callerInfoOpt.Span, Me.Compilation.Options.SourceReferenceResolver)) Else Debug.Assert(callerArgumentExpressionParameterIndex > -1 OrElse (reducedExtensionReceiverOpt IsNot Nothing AndAlso callerArgumentExpressionParameterIndex > -2)) Dim argumentSyntax As SyntaxNode = Nothing If callerArgumentExpressionParameterIndex = -1 Then argumentSyntax = reducedExtensionReceiverOpt.Syntax Else Dim argumentIndex = parameterToArgumentMap(callerArgumentExpressionParameterIndex) Debug.Assert(argumentIndex < arguments.Length) If argumentIndex > -1 Then argumentSyntax = arguments(argumentIndex).Syntax End If End If If argumentSyntax IsNot Nothing Then callerInfoValue = ConstantValue.Create(argumentSyntax.ToString()) End If End If If callerInfoValue IsNot Nothing Then ' Use the value only if it will not cause errors. Dim ignoreDiagnostics = BindingDiagnosticBag.GetInstance(withDiagnostics:=True, withDependencies:=False) Dim literal As BoundLiteral If callerInfoValue.Discriminator = ConstantValueTypeDiscriminator.Int32 Then literal = New BoundLiteral(syntax, callerInfoValue, GetSpecialType(SpecialType.System_Int32, syntax, ignoreDiagnostics)) Else Debug.Assert(callerInfoValue.Discriminator = ConstantValueTypeDiscriminator.String) literal = New BoundLiteral(syntax, callerInfoValue, GetSpecialType(SpecialType.System_String, syntax, ignoreDiagnostics)) End If Dim convertedValue As BoundExpression = ApplyImplicitConversion(syntax, param.Type, literal, ignoreDiagnostics) If Not convertedValue.HasErrors AndAlso Not ignoreDiagnostics.HasAnyErrors Then ' Dev11 #248795: Caller info should be omitted if user defined conversion is involved. If Not (convertedValue.Kind = BoundKind.Conversion AndAlso (DirectCast(convertedValue, BoundConversion).ConversionKind And ConversionKind.UserDefined) <> 0) Then defaultConstantValue = callerInfoValue End If End If ignoreDiagnostics.Free() End If End If End If ' For compatibility with the native compiler bad metadata constants should be treated as default(T). This ' is a possible outcome of running an obfuscator over a valid DLL If defaultConstantValue.IsBad Then defaultConstantValue = ConstantValue.Null End If Dim defaultSpecialType = defaultConstantValue.SpecialType Dim defaultArgumentType As TypeSymbol = Nothing ' Constant has a type. Dim paramNullableUnderlyingTypeOrSelf As TypeSymbol = param.Type.GetNullableUnderlyingTypeOrSelf() If param.HasOptionCompare Then ' If the argument has the OptionCompareAttribute ' then use the setting for Option Compare [Binary|Text] ' Other languages will use the default value specified. If Me.OptionCompareText Then defaultConstantValue = ConstantValue.Create(1) Else defaultConstantValue = ConstantValue.Default(SpecialType.System_Int32) End If If paramNullableUnderlyingTypeOrSelf.GetEnumUnderlyingTypeOrSelf().SpecialType = SpecialType.System_Int32 Then defaultArgumentType = paramNullableUnderlyingTypeOrSelf Else defaultArgumentType = GetSpecialType(SpecialType.System_Int32, syntax, diagnostics) End If ElseIf defaultSpecialType <> SpecialType.None Then If paramNullableUnderlyingTypeOrSelf.GetEnumUnderlyingTypeOrSelf().SpecialType = defaultSpecialType Then ' Enum default values are encoded as the underlying primitive type. If the underlying types match then ' use the parameter's enum type. defaultArgumentType = paramNullableUnderlyingTypeOrSelf Else 'Use the primitive type. defaultArgumentType = GetSpecialType(defaultSpecialType, syntax, diagnostics) End If Else ' No type in constant. Constant should be nothing Debug.Assert(defaultConstantValue.IsNothing) End If defaultArgument = New BoundLiteral(syntax, defaultConstantValue, defaultArgumentType) ElseIf param.IsOptional Then ' Handle optional object type argument when no default value is specified. ' Section 3 of §11.8.2 Applicable Methods If param.Type.SpecialType = SpecialType.System_Object Then Dim methodSymbol As MethodSymbol = Nothing If param.IsMarshalAsObject Then ' Nothing defaultArgument = New BoundLiteral(syntax, ConstantValue.Null, Nothing) ElseIf param.IsIDispatchConstant Then ' new DispatchWrapper(nothing) methodSymbol = DirectCast(GetWellKnownTypeMember(WellKnownMember.System_Runtime_InteropServices_DispatchWrapper__ctor, syntax, diagnostics), MethodSymbol) ElseIf param.IsIUnknownConstant Then ' new UnknownWrapper(nothing) methodSymbol = DirectCast(GetWellKnownTypeMember(WellKnownMember.System_Runtime_InteropServices_UnknownWrapper__ctor, syntax, diagnostics), MethodSymbol) Else defaultArgument = New BoundOmittedArgument(syntax, param.Type) End If If methodSymbol IsNot Nothing Then Dim argument = New BoundLiteral(syntax, ConstantValue.Null, param.Type).MakeCompilerGenerated() defaultArgument = New BoundObjectCreationExpression(syntax, methodSymbol, ImmutableArray.Create(Of BoundExpression)(argument), Nothing, methodSymbol.ContainingType) End If Else defaultArgument = New BoundLiteral(syntax, ConstantValue.Null, Nothing) End If End If Return defaultArgument?.MakeCompilerGenerated() End Function Private Shared Function GetCallerLocation(syntax As SyntaxNode) As TextSpan Select Case syntax.Kind Case SyntaxKind.SimpleMemberAccessExpression Return DirectCast(syntax, MemberAccessExpressionSyntax).Name.Span Case SyntaxKind.DictionaryAccessExpression Return DirectCast(syntax, MemberAccessExpressionSyntax).OperatorToken.Span Case Else Return syntax.Span End Select End Function ''' <summary> ''' Return true if the node is an immediate child of a call statement. ''' </summary> Private Shared Function IsCallStatementContext(node As InvocationExpressionSyntax) As Boolean Dim parent As VisualBasicSyntaxNode = node.Parent ' Dig through conditional access If parent IsNot Nothing AndAlso parent.Kind = SyntaxKind.ConditionalAccessExpression Then Dim conditional = DirectCast(parent, ConditionalAccessExpressionSyntax) If conditional.WhenNotNull Is node Then parent = conditional.Parent End If End If Return parent IsNot Nothing AndAlso (parent.Kind = SyntaxKind.CallStatement OrElse parent.Kind = SyntaxKind.ExpressionStatement) End Function End Class End Namespace