/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Semantics/OverloadResolution.vb
5 369 строк
267 KB
Jan Jones
Validate pooled objects in compiler tests (#82784)
15 май 2026, 09:55
Не верифицирован
15 май 2026, 09:55
e141f0d
Код
Авторство
О чём код?
' 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.Diagnostics Imports System.Linq Imports System.Runtime.InteropServices Imports Microsoft.CodeAnalysis.Collections Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.VisualBasicSyntaxTree Imports TypeKind = Microsoft.CodeAnalysis.TypeKind Namespace Microsoft.CodeAnalysis.VisualBasic Friend NotInheritable Class OverloadResolution Private Sub New() Throw ExceptionUtilities.Unreachable End Sub ''' <summary> ''' Information about a candidate from a group. ''' Will have different implementation for methods, extension methods and properties. ''' </summary> ''' <remarks></remarks> Public MustInherit Class Candidate Public MustOverride ReadOnly Property UnderlyingSymbol As Symbol Friend MustOverride Function Construct(typeArguments As ImmutableArray(Of TypeSymbol)) As Candidate ''' <summary> ''' Whether the method is used as extension method vs. called as a static method. ''' </summary> Public Overridable ReadOnly Property IsExtensionMethod As Boolean Get Return False End Get End Property ''' <summary> ''' Whether the method is used as an operator. ''' </summary> Public Overridable ReadOnly Property IsOperator As Boolean Get Return False End Get End Property ''' <summary> ''' Whether the method is used in a lifted to nullable form. ''' </summary> Public Overridable ReadOnly Property IsLifted As Boolean Get Return False End Get End Property ''' <summary> ''' Precedence level for an extension method. ''' </summary> Public Overridable ReadOnly Property PrecedenceLevel As Integer Get Return 0 End Get End Property ''' <summary> ''' Extension method type parameters that were fixed during currying, if any. ''' If none were fixed, BitArray.Null should be returned. ''' </summary> Public Overridable ReadOnly Property FixedTypeParameters As BitVector Get Return BitVector.Null End Get End Property Public MustOverride ReadOnly Property IsGeneric As Boolean Public MustOverride ReadOnly Property ParameterCount As Integer Public MustOverride Function Parameters(index As Integer) As ParameterSymbol Public MustOverride ReadOnly Property ReturnType As TypeSymbol Public MustOverride ReadOnly Property Arity As Integer Public MustOverride ReadOnly Property TypeParameters As ImmutableArray(Of TypeParameterSymbol) Public MustOverride ReadOnly Property OverloadResolutionPriority As Integer Public MustOverride Function GetOverloadResolutionPriorityInfo() As (Source As NamedTypeSymbol, Priority As Integer) Friend Sub GetAllParameterCounts( ByRef requiredCount As Integer, ByRef maxCount As Integer, ByRef hasParamArray As Boolean ) maxCount = Me.ParameterCount hasParamArray = False requiredCount = -1 Dim last = maxCount - 1 For i As Integer = 0 To last Step 1 Dim param As ParameterSymbol = Me.Parameters(i) If i = last AndAlso param.IsParamArray Then hasParamArray = True ElseIf Not param.IsOptional Then requiredCount = i End If Next requiredCount += 1 End Sub Friend Function TryGetNamedParamIndex(name As String, ByRef index As Integer) As Boolean For i As Integer = 0 To Me.ParameterCount - 1 Step 1 Dim param As ParameterSymbol = Me.Parameters(i) If IdentifierComparison.Equals(name, param.Name) Then index = i Return True End If Next index = -1 Return False End Function ''' <summary> ''' Receiver type for extension method. Otherwise, containing type. ''' </summary> Public MustOverride ReadOnly Property ReceiverType As TypeSymbol ''' <summary> ''' For extension methods, the type of the fist parameter in method's definition (i.e. before type parameters are substituted). ''' Otherwise, same as the ReceiverType. ''' </summary> Public MustOverride ReadOnly Property ReceiverTypeDefinition As TypeSymbol Friend MustOverride Function IsOverriddenBy(otherSymbol As Symbol) As Boolean End Class ''' <summary> ''' Implementation for an ordinary method (based on usage). ''' </summary> Public Class MethodCandidate Inherits Candidate Protected ReadOnly m_Method As MethodSymbol Public Sub New(method As MethodSymbol) Debug.Assert(method IsNot Nothing) Debug.Assert(method.ReducedFrom Is Nothing OrElse Me.IsExtensionMethod) m_Method = method End Sub Friend Overrides Function Construct(typeArguments As ImmutableArray(Of TypeSymbol)) As Candidate Return New MethodCandidate(m_Method.Construct(typeArguments)) End Function Public Overrides ReadOnly Property IsGeneric As Boolean Get Return m_Method.IsGenericMethod End Get End Property Public Overrides ReadOnly Property ParameterCount As Integer Get Return m_Method.ParameterCount End Get End Property Public Overrides Function Parameters(index As Integer) As ParameterSymbol Return m_Method.Parameters(index) End Function Public Overrides ReadOnly Property ReturnType As TypeSymbol Get Return m_Method.ReturnType End Get End Property Public Overrides ReadOnly Property ReceiverType As TypeSymbol Get Return m_Method.ContainingType End Get End Property Public Overrides ReadOnly Property ReceiverTypeDefinition As TypeSymbol Get Return m_Method.ContainingType End Get End Property Public Overrides ReadOnly Property Arity As Integer Get Return m_Method.Arity End Get End Property Public Overrides ReadOnly Property TypeParameters As ImmutableArray(Of TypeParameterSymbol) Get Return m_Method.TypeParameters End Get End Property Public Overrides ReadOnly Property UnderlyingSymbol As Symbol Get Return m_Method End Get End Property Friend Overrides Function IsOverriddenBy(otherSymbol As Symbol) As Boolean Dim definition As MethodSymbol = m_Method.OriginalDefinition If definition.IsOverridable OrElse definition.IsOverrides OrElse definition.IsMustOverride Then Dim otherMethod As MethodSymbol = DirectCast(otherSymbol, MethodSymbol).OverriddenMethod While otherMethod IsNot Nothing If otherMethod.OriginalDefinition.Equals(definition) Then Return True End If otherMethod = otherMethod.OverriddenMethod End While End If Return False End Function Public Overrides ReadOnly Property OverloadResolutionPriority As Integer Get Return m_Method.OriginalDefinition.OverloadResolutionPriority End Get End Property Public Overrides Function GetOverloadResolutionPriorityInfo() As (Source As NamedTypeSymbol, Priority As Integer) Dim leastOverriddenDefinition As MethodSymbol = m_Method.OriginalDefinition While leastOverriddenDefinition.IsOverrides Dim overridden As MethodSymbol = leastOverriddenDefinition.OverriddenMethod If overridden Is Nothing Then Exit While End If leastOverriddenDefinition = overridden.OriginalDefinition End While Return (leastOverriddenDefinition.ContainingType, leastOverriddenDefinition.OverloadResolutionPriority) End Function End Class ''' <summary> ''' Implementation for an extension method, i.e. it is used as an extension method. ''' </summary> Public NotInheritable Class ExtensionMethodCandidate Inherits MethodCandidate Private _fixedTypeParameters As BitVector Public Sub New(method As MethodSymbol) Me.New(method, GetFixedTypeParameters(method)) End Sub ' TODO: Consider building this bitmap lazily, on demand. Private Shared Function GetFixedTypeParameters(method As MethodSymbol) As BitVector If method.FixedTypeParameters.Length > 0 Then Dim fixedTypeParameters = BitVector.Create(method.ReducedFrom.Arity) For Each fixed As KeyValuePair(Of TypeParameterSymbol, TypeSymbol) In method.FixedTypeParameters fixedTypeParameters(fixed.Key.Ordinal) = True Next Return fixedTypeParameters End If Return Nothing End Function Private Sub New(method As MethodSymbol, fixedTypeParameters As BitVector) MyBase.New(method) Debug.Assert(method.ReducedFrom IsNot Nothing) _fixedTypeParameters = fixedTypeParameters End Sub Public Overrides ReadOnly Property IsExtensionMethod As Boolean Get Return True End Get End Property Public Overrides ReadOnly Property PrecedenceLevel As Integer Get Return m_Method.Proximity End Get End Property Public Overrides ReadOnly Property FixedTypeParameters As BitVector Get Return _fixedTypeParameters End Get End Property Friend Overrides Function Construct(typeArguments As ImmutableArray(Of TypeSymbol)) As Candidate Return New ExtensionMethodCandidate(m_Method.Construct(typeArguments), _fixedTypeParameters) End Function Public Overrides ReadOnly Property ReceiverType As TypeSymbol Get Return m_Method.ReceiverType End Get End Property Public Overrides ReadOnly Property ReceiverTypeDefinition As TypeSymbol Get Return m_Method.ReducedFrom.Parameters(0).Type End Get End Property Friend Overrides Function IsOverriddenBy(otherSymbol As Symbol) As Boolean Return False ' Extension methods never override/overridden End Function End Class ''' <summary> ''' Implementation for an operator ''' </summary> Public Class OperatorCandidate Inherits MethodCandidate Public Sub New(method As MethodSymbol) MyBase.New(method) End Sub Public NotOverridable Overrides ReadOnly Property IsOperator As Boolean Get Return True End Get End Property End Class ''' <summary> ''' Implementation for a lifted operator. ''' </summary> Public Class LiftedOperatorCandidate Inherits OperatorCandidate Private ReadOnly _parameters As ImmutableArray(Of ParameterSymbol) Private ReadOnly _returnType As TypeSymbol Public Sub New(method As MethodSymbol, parameters As ImmutableArray(Of ParameterSymbol), returnType As TypeSymbol) MyBase.New(method) Debug.Assert(parameters.Length = method.ParameterCount) _parameters = parameters _returnType = returnType End Sub Public Overrides ReadOnly Property ParameterCount As Integer Get Return _parameters.Length End Get End Property Public Overrides Function Parameters(index As Integer) As ParameterSymbol Return _parameters(index) End Function Public Overrides ReadOnly Property ReturnType As TypeSymbol Get Return _returnType End Get End Property Public Overrides ReadOnly Property IsLifted As Boolean Get Return True End Get End Property End Class ''' <summary> ''' Implementation for a property. ''' </summary> Public NotInheritable Class PropertyCandidate Inherits Candidate Private ReadOnly _property As PropertySymbol Public Sub New([property] As PropertySymbol) Debug.Assert([property] IsNot Nothing) _property = [property] End Sub Friend Overrides Function Construct(typeArguments As ImmutableArray(Of TypeSymbol)) As Candidate Throw ExceptionUtilities.Unreachable End Function Public Overrides ReadOnly Property IsGeneric As Boolean Get Return False End Get End Property Public Overrides ReadOnly Property ParameterCount As Integer Get Return _property.Parameters.Length End Get End Property Public Overrides Function Parameters(index As Integer) As ParameterSymbol Return _property.Parameters(index) End Function Public Overrides ReadOnly Property ReturnType As TypeSymbol Get Return _property.Type End Get End Property Public Overrides ReadOnly Property ReceiverType As TypeSymbol Get Return _property.ContainingType End Get End Property Public Overrides ReadOnly Property ReceiverTypeDefinition As TypeSymbol Get Return _property.ContainingType End Get End Property Public Overrides ReadOnly Property Arity As Integer Get Return 0 End Get End Property Public Overrides ReadOnly Property TypeParameters As ImmutableArray(Of TypeParameterSymbol) Get Return ImmutableArray(Of TypeParameterSymbol).Empty End Get End Property Public Overrides ReadOnly Property UnderlyingSymbol As Symbol Get Return _property End Get End Property Friend Overrides Function IsOverriddenBy(otherSymbol As Symbol) As Boolean Dim definition As PropertySymbol = _property.OriginalDefinition If definition.IsOverridable OrElse definition.IsOverrides OrElse definition.IsMustOverride Then Dim otherProperty As PropertySymbol = DirectCast(otherSymbol, PropertySymbol).OverriddenProperty While otherProperty IsNot Nothing If otherProperty.OriginalDefinition.Equals(definition) Then Return True End If otherProperty = otherProperty.OverriddenProperty End While End If Return False End Function Public Overrides ReadOnly Property OverloadResolutionPriority As Integer Get Return _property.OriginalDefinition.OverloadResolutionPriority End Get End Property Public Overrides Function GetOverloadResolutionPriorityInfo() As (Source As NamedTypeSymbol, Priority As Integer) Dim leastOverriddenDefinition As PropertySymbol = _property.OriginalDefinition While leastOverriddenDefinition.IsOverrides Dim overridden As PropertySymbol = leastOverriddenDefinition.OverriddenProperty If overridden Is Nothing Then Exit While End If leastOverriddenDefinition = overridden.OriginalDefinition End While Return (leastOverriddenDefinition.ContainingType, leastOverriddenDefinition.OverloadResolutionPriority) End Function End Class Private Const s_stateSize = 8 ' bit size of the following enum Public Enum CandidateAnalysisResultState As Byte Applicable ' All following states are to indicate inapplicability HasUnsupportedMetadata HasUseSiteError Ambiguous BadGenericArity ArgumentCountMismatch TypeInferenceFailed ArgumentMismatch GenericConstraintsViolated RequiresNarrowing RequiresNarrowingNotFromObject ExtensionMethodVsInstanceMethod Shadowed LessApplicable ExtensionMethodVsLateBinding Count End Enum <Flags()> Private Enum SmallFieldMask As Integer State = (1 << s_stateSize) - 1 IsExpandedParamArrayForm = 1 << (s_stateSize + 0) InferenceLevelShift = (s_stateSize + 1) InferenceLevelMask = 3 << InferenceLevelShift ' 2 bits are used ArgumentMatchingDone = 1 << (s_stateSize + 3) RequiresNarrowingConversion = 1 << (s_stateSize + 4) RequiresNarrowingNotFromObject = 1 << (s_stateSize + 5) RequiresNarrowingNotFromNumericConstant = 1 << (s_stateSize + 6) ' Must be equal to ConversionKind.DelegateRelaxationLevelMask ' Compile time "asserts" below enforce it by reporting a compilation error in case of a violation. ' I am not using the form of ' DelegateRelaxationLevelMask = ConversionKind.DelegateRelaxationLevelMask ' to make it easier to reason about bits used relative to other values in this enum. DelegateRelaxationLevelMask = 7 << (s_stateSize + 7) ' 3 bits used! SomeInferenceFailed = 1 << (s_stateSize + 10) AllFailedInferenceIsDueToObject = 1 << (s_stateSize + 11) InferenceErrorReasonsShift = (s_stateSize + 12) InferenceErrorReasonsMask = 3 << InferenceErrorReasonsShift IgnoreExtensionMethods = 1 << (s_stateSize + 14) IllegalInAttribute = 1 << (s_stateSize + 15) End Enum #If DEBUG Then ' Compile time asserts. #Disable Warning IDE0051 ' Remove unused private members Private Const s_delegateRelaxationLevelMask_AssertZero = SmallFieldMask.DelegateRelaxationLevelMask - ConversionKind.DelegateRelaxationLevelMask Private ReadOnly _delegateRelaxationLevelMask_Assert1(s_delegateRelaxationLevelMask_AssertZero) As Boolean Private ReadOnly _delegateRelaxationLevelMask_Assert2(-s_delegateRelaxationLevelMask_AssertZero) As Boolean Private Const s_inferenceLevelMask_AssertZero = CByte((SmallFieldMask.InferenceLevelMask >> SmallFieldMask.InferenceLevelShift) <> ((TypeArgumentInference.InferenceLevel.Invalid << 1) - 1)) Private ReadOnly _inferenceLevelMask_Assert1(s_inferenceLevelMask_AssertZero) As Boolean Private ReadOnly _inferenceLevelMask_Assert2(-s_inferenceLevelMask_AssertZero) As Boolean #Enable Warning IDE0051 ' Remove unused private members #End If Public Structure OptionalArgument Public ReadOnly DefaultValue As BoundExpression Public ReadOnly Conversion As KeyValuePair(Of ConversionKind, MethodSymbol) Public ReadOnly Dependencies As ImmutableArray(Of AssemblySymbol) Public Sub New(value As BoundExpression, conversion As KeyValuePair(Of ConversionKind, MethodSymbol), dependencies As ImmutableArray(Of AssemblySymbol)) Me.DefaultValue = value Me.Conversion = conversion Me.Dependencies = dependencies.NullToEmpty() End Sub End Structure Public Structure CandidateAnalysisResult Public ReadOnly Property IsExpandedParamArrayForm As Boolean Get Return (_smallFields And SmallFieldMask.IsExpandedParamArrayForm) <> 0 End Get End Property Public Sub SetIsExpandedParamArrayForm() _smallFields = _smallFields Or SmallFieldMask.IsExpandedParamArrayForm End Sub Public ReadOnly Property InferenceLevel As TypeArgumentInference.InferenceLevel Get Return CType((_smallFields And SmallFieldMask.InferenceLevelMask) >> SmallFieldMask.InferenceLevelShift, TypeArgumentInference.InferenceLevel) End Get End Property Public Sub SetInferenceLevel(level As TypeArgumentInference.InferenceLevel) Dim value As Integer = CInt(level) << SmallFieldMask.InferenceLevelShift Debug.Assert((value And SmallFieldMask.InferenceLevelMask) = value) _smallFields = (_smallFields And (Not SmallFieldMask.InferenceLevelMask)) Or (value And SmallFieldMask.InferenceLevelMask) End Sub Public ReadOnly Property ArgumentMatchingDone As Boolean Get Return (_smallFields And SmallFieldMask.ArgumentMatchingDone) <> 0 End Get End Property Public Sub SetArgumentMatchingDone() _smallFields = _smallFields Or SmallFieldMask.ArgumentMatchingDone End Sub Public ReadOnly Property RequiresNarrowingConversion As Boolean Get Return (_smallFields And SmallFieldMask.RequiresNarrowingConversion) <> 0 End Get End Property Public Sub SetRequiresNarrowingConversion() _smallFields = _smallFields Or SmallFieldMask.RequiresNarrowingConversion End Sub Public ReadOnly Property RequiresNarrowingNotFromObject As Boolean Get Return (_smallFields And SmallFieldMask.RequiresNarrowingNotFromObject) <> 0 End Get End Property Public Sub SetRequiresNarrowingNotFromObject() _smallFields = _smallFields Or SmallFieldMask.RequiresNarrowingNotFromObject End Sub Public ReadOnly Property RequiresNarrowingNotFromNumericConstant As Boolean Get Return (_smallFields And SmallFieldMask.RequiresNarrowingNotFromNumericConstant) <> 0 End Get End Property Public Sub SetRequiresNarrowingNotFromNumericConstant() Debug.Assert(RequiresNarrowingConversion) IgnoreExtensionMethods = False _smallFields = _smallFields Or SmallFieldMask.RequiresNarrowingNotFromNumericConstant End Sub ''' <summary> ''' Only bits specific to delegate relaxation level are returned. ''' </summary> Public ReadOnly Property MaxDelegateRelaxationLevel As ConversionKind Get Return CType(_smallFields And SmallFieldMask.DelegateRelaxationLevelMask, ConversionKind) End Get End Property Public Sub RegisterDelegateRelaxationLevel(conversionKind As ConversionKind) Dim relaxationLevel As Integer = (conversionKind And SmallFieldMask.DelegateRelaxationLevelMask) If relaxationLevel > (_smallFields And SmallFieldMask.DelegateRelaxationLevelMask) Then Debug.Assert(relaxationLevel <= ConversionKind.DelegateRelaxationLevelNarrowing) If relaxationLevel = ConversionKind.DelegateRelaxationLevelNarrowing Then IgnoreExtensionMethods = False End If _smallFields = (_smallFields And (Not SmallFieldMask.DelegateRelaxationLevelMask)) Or relaxationLevel End If End Sub Public Sub SetSomeInferenceFailed() _smallFields = _smallFields Or SmallFieldMask.SomeInferenceFailed End Sub Public ReadOnly Property SomeInferenceFailed As Boolean Get Return (_smallFields And SmallFieldMask.SomeInferenceFailed) <> 0 End Get End Property Public Sub SetIllegalInAttribute() _smallFields = _smallFields Or SmallFieldMask.IllegalInAttribute End Sub Public ReadOnly Property IsIllegalInAttribute As Boolean Get Return (_smallFields And SmallFieldMask.IllegalInAttribute) <> 0 End Get End Property Public Sub SetAllFailedInferenceIsDueToObject() _smallFields = _smallFields Or SmallFieldMask.AllFailedInferenceIsDueToObject End Sub Public ReadOnly Property AllFailedInferenceIsDueToObject As Boolean Get Return (_smallFields And SmallFieldMask.AllFailedInferenceIsDueToObject) <> 0 End Get End Property Public Sub SetInferenceErrorReasons(reasons As InferenceErrorReasons) Dim value As Integer = CInt(reasons) << SmallFieldMask.InferenceErrorReasonsShift Debug.Assert((value And SmallFieldMask.InferenceErrorReasonsMask) = value) _smallFields = (_smallFields And (Not SmallFieldMask.InferenceErrorReasonsMask)) Or (value And SmallFieldMask.InferenceErrorReasonsMask) End Sub Public ReadOnly Property InferenceErrorReasons As InferenceErrorReasons Get Return CType((_smallFields And SmallFieldMask.InferenceErrorReasonsMask) >> SmallFieldMask.InferenceErrorReasonsShift, InferenceErrorReasons) End Get End Property Public Property State As CandidateAnalysisResultState Get Return CType(_smallFields And SmallFieldMask.State, CandidateAnalysisResultState) End Get Set(value As CandidateAnalysisResultState) Debug.Assert((value And (Not SmallFieldMask.State)) = 0) Dim newFields = _smallFields And (Not SmallFieldMask.State) newFields = newFields Or value _smallFields = newFields End Set End Property Public Property IgnoreExtensionMethods As Boolean Get Return (_smallFields And SmallFieldMask.IgnoreExtensionMethods) <> 0 End Get Set(value As Boolean) If value Then _smallFields = _smallFields Or SmallFieldMask.IgnoreExtensionMethods Else _smallFields = _smallFields And (Not SmallFieldMask.IgnoreExtensionMethods) End If End Set End Property Private _smallFields As Integer Public Candidate As Candidate Public ExpandedParamArrayArgumentsUsed As Integer Public EquallyApplicableCandidatesBucket As Integer ' When this is null, it means that arguments map to parameters sequentially Public ArgsToParamsOpt As ImmutableArray(Of Integer) ' When these are null, it means that all conversions are identity conversions Public ConversionsOpt As ImmutableArray(Of KeyValuePair(Of ConversionKind, MethodSymbol)) Public ConversionsBackOpt As ImmutableArray(Of KeyValuePair(Of ConversionKind, MethodSymbol)) ' When this is null, it means that there aren't any optional arguments ' This array is indexed by parameter index, not the argument index. Public OptionalArguments As ImmutableArray(Of OptionalArgument) Public ReadOnly Property UsedOptionalParameterDefaultValue As Boolean Get Return Not OptionalArguments.IsDefault End Get End Property Public NotInferredTypeArguments As BitVector Public TypeArgumentInferenceDiagnosticsOpt As ReadOnlyBindingDiagnostic(Of AssemblySymbol) Public Sub New(candidate As Candidate, state As CandidateAnalysisResultState) Me.Candidate = candidate Me.State = state End Sub Public Sub New(candidate As Candidate) Me.Candidate = candidate Me.State = CandidateAnalysisResultState.Applicable End Sub End Structure ' Represents a simple overload resolution result Friend Structure OverloadResolutionResult Private ReadOnly _bestResult As CandidateAnalysisResult? Private ReadOnly _allResults As ImmutableArray(Of CandidateAnalysisResult) Private ReadOnly _resolutionIsLateBound As Boolean Private ReadOnly _remainingCandidatesRequireNarrowingConversion As Boolean Public ReadOnly AsyncLambdaSubToFunctionMismatch As ImmutableArray(Of BoundExpression) ' Create an overload resolution result from a full set of results. Public Sub New(allResults As ImmutableArray(Of CandidateAnalysisResult), resolutionIsLateBound As Boolean, remainingCandidatesRequireNarrowingConversion As Boolean, asyncLambdaSubToFunctionMismatch As HashSet(Of BoundExpression)) Me._allResults = allResults Me._resolutionIsLateBound = resolutionIsLateBound Me._remainingCandidatesRequireNarrowingConversion = remainingCandidatesRequireNarrowingConversion Me.AsyncLambdaSubToFunctionMismatch = If(asyncLambdaSubToFunctionMismatch Is Nothing, ImmutableArray(Of BoundExpression).Empty, asyncLambdaSubToFunctionMismatch.ToArray().AsImmutableOrNull()) If Not resolutionIsLateBound Then Me._bestResult = GetBestResult(allResults) End If End Sub Public ReadOnly Property Candidates As ImmutableArray(Of CandidateAnalysisResult) Get Return _allResults End Get End Property ' Returns the best method. Note that if overload resolution succeeded, the set of conversion kinds will NOT be returned. Public ReadOnly Property BestResult As CandidateAnalysisResult? Get Return _bestResult End Get End Property Public ReadOnly Property ResolutionIsLateBound As Boolean Get Return _resolutionIsLateBound End Get End Property ''' <summary> ''' This might simplify error reporting. If not, consider getting rid of this property. ''' </summary> Public ReadOnly Property RemainingCandidatesRequireNarrowingConversion As Boolean Get Return _remainingCandidatesRequireNarrowingConversion End Get End Property Private Shared Function GetBestResult(allResults As ImmutableArray(Of CandidateAnalysisResult)) As CandidateAnalysisResult? Dim best As CandidateAnalysisResult? = Nothing Dim i As Integer = 0 While i < allResults.Length Dim current = allResults(i) If current.State = CandidateAnalysisResultState.Applicable Then If best IsNot Nothing Then Return Nothing End If best = current End If i = i + 1 End While Return best End Function End Structure ''' <summary> ''' Perform overload resolution on the given method or property group, with the given arguments and names. ''' The names can be null if no names were supplied to any arguments. ''' </summary> Public Shared Function MethodOrPropertyInvocationOverloadResolution( group As BoundMethodOrPropertyGroup, arguments As ImmutableArray(Of BoundExpression), argumentNames As ImmutableArray(Of String), binder As Binder, callerInfoOpt As SyntaxNode, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol), Optional includeEliminatedCandidates As Boolean = False, Optional forceExpandedForm As Boolean = False ) As OverloadResolutionResult If group.Kind = BoundKind.MethodGroup Then Dim methodGroup = DirectCast(group, BoundMethodGroup) Return MethodInvocationOverloadResolution( methodGroup, arguments, argumentNames, binder, callerInfoOpt, useSiteInfo, includeEliminatedCandidates, forceExpandedForm:=forceExpandedForm) Else Dim propertyGroup = DirectCast(group, BoundPropertyGroup) Return PropertyInvocationOverloadResolution( propertyGroup, arguments, argumentNames, binder, callerInfoOpt, useSiteInfo, includeEliminatedCandidates) End If End Function ''' <summary> ''' Perform overload resolution on the given method group, with the given arguments. ''' </summary> Public Shared Function QueryOperatorInvocationOverloadResolution( methodGroup As BoundMethodGroup, arguments As ImmutableArray(Of BoundExpression), binder As Binder, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol), Optional includeEliminatedCandidates As Boolean = False ) As OverloadResolutionResult Return MethodInvocationOverloadResolution( methodGroup, arguments, Nothing, binder, callerInfoOpt:=Nothing, useSiteInfo:=useSiteInfo, includeEliminatedCandidates:=includeEliminatedCandidates, lateBindingIsAllowed:=False, isQueryOperatorInvocation:=True) End Function ''' <summary> ''' Perform overload resolution on the given method group, with the given arguments and names. ''' The names can be null if no names were supplied to any arguments. ''' </summary> Public Shared Function MethodInvocationOverloadResolution( methodGroup As BoundMethodGroup, arguments As ImmutableArray(Of BoundExpression), argumentNames As ImmutableArray(Of String), binder As Binder, callerInfoOpt As SyntaxNode, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol), Optional includeEliminatedCandidates As Boolean = False, Optional delegateReturnType As TypeSymbol = Nothing, Optional delegateReturnTypeReferenceBoundNode As BoundNode = Nothing, Optional lateBindingIsAllowed As Boolean = True, Optional isQueryOperatorInvocation As Boolean = False, Optional forceExpandedForm As Boolean = False ) As OverloadResolutionResult Debug.Assert(methodGroup.ResultKind = LookupResultKind.Good OrElse methodGroup.ResultKind = LookupResultKind.Inaccessible) Dim typeArguments = If(methodGroup.TypeArgumentsOpt IsNot Nothing, methodGroup.TypeArgumentsOpt.Arguments, ImmutableArray(Of TypeSymbol).Empty) ' To simplify code later If typeArguments.IsDefault Then typeArguments = ImmutableArray(Of TypeSymbol).Empty End If If arguments.IsDefault Then arguments = ImmutableArray(Of BoundExpression).Empty End If Dim candidates = ArrayBuilder(Of CandidateAnalysisResult).GetInstance() Dim instanceCandidates As ArrayBuilder(Of Candidate) = ArrayBuilder(Of Candidate).GetInstance() Dim curriedCandidates As ArrayBuilder(Of Candidate) = ArrayBuilder(Of Candidate).GetInstance() Dim methods As ImmutableArray(Of MethodSymbol) = methodGroup.Methods If Not methods.IsDefault Then ' Create MethodCandidates for ordinary methods and ExtensionMethodCandidates ' for curried methods, separating them. For Each method As MethodSymbol In methods If method.ReducedFrom Is Nothing Then instanceCandidates.Add(New MethodCandidate(method)) Else curriedCandidates.Add(New ExtensionMethodCandidate(method)) End If Next End If Dim asyncLambdaSubToFunctionMismatch As HashSet(Of BoundExpression) = Nothing Dim applicableNarrowingCandidateCount As Integer = 0 Dim applicableInstanceCandidateCount As Integer = 0 Dim someCandidatesHaveOverloadResolutionPriority As Boolean = False Dim respectOverloadResolutionPriority As Boolean = InternalSyntax.Parser.CheckFeatureAvailability(binder.Compilation.LanguageVersion, InternalSyntax.Feature.OverloadResolutionPriority) If respectOverloadResolutionPriority AndAlso binder.IsEarlyAttributeBinder Then Dim possiblyConstructor = TryCast(binder.ContainingMember, MethodSymbol) If possiblyConstructor IsNot Nothing AndAlso possiblyConstructor.MethodKind = MethodKind.Constructor AndAlso possiblyConstructor.ContainingType.Name = AttributeDescription.OverloadResolutionPriorityAttribute.Name AndAlso possiblyConstructor.ContainingType.IsCompilerServicesTopLevelType() Then ' Avoid possible cycle during attribute binding respectOverloadResolutionPriority = False End If End If ' First collect instance methods. If instanceCandidates.Count > 0 Then ' Given the way VB name lookup works, the least derived forms are also among the candidates and are getting filtered out by CombineCandidates. ' Therefore, this simple check gets to them as well without explicitly traversing the overrides hierarchy. someCandidatesHaveOverloadResolutionPriority = respectOverloadResolutionPriority AndAlso instanceCandidates.Any(Function(candidate) candidate.OverloadResolutionPriority <> 0) CollectOverloadedCandidates( binder, candidates, instanceCandidates, typeArguments, arguments, argumentNames, someCandidatesHaveOverloadResolutionPriority, delegateReturnType, delegateReturnTypeReferenceBoundNode, includeEliminatedCandidates, isQueryOperatorInvocation, forceExpandedForm, asyncLambdaSubToFunctionMismatch, useSiteInfo) applicableInstanceCandidateCount = EliminateNotApplicableToArguments(methodGroup, candidates, arguments, argumentNames, binder, applicableNarrowingCandidateCount, asyncLambdaSubToFunctionMismatch, callerInfoOpt, forceExpandedForm, useSiteInfo) End If instanceCandidates.Free() instanceCandidates = Nothing ' Now add extension methods if they should be considered. Dim addedExtensionMethods As Boolean = False If ShouldConsiderExtensionMethods(candidates) Then Debug.Assert(candidates.All(Function(candidate) candidate.State <> CandidateAnalysisResultState.Applicable OrElse candidate.RequiresNarrowingConversion OrElse candidate.MaxDelegateRelaxationLevel = ConversionKind.DelegateRelaxationLevelNarrowing)) ' Request additional extension methods, if any available. If methodGroup.ResultKind = LookupResultKind.Good Then methods = methodGroup.AdditionalExtensionMethods(useSiteInfo) For Each method As MethodSymbol In methods curriedCandidates.Add(New ExtensionMethodCandidate(method)) Next End If If curriedCandidates.Count > 0 Then addedExtensionMethods = True someCandidatesHaveOverloadResolutionPriority = someCandidatesHaveOverloadResolutionPriority OrElse (respectOverloadResolutionPriority AndAlso curriedCandidates.Any(Function(candidate) candidate.OverloadResolutionPriority <> 0)) CollectOverloadedCandidates( binder, candidates, curriedCandidates, typeArguments, arguments, argumentNames, someCandidatesHaveOverloadResolutionPriority, delegateReturnType, delegateReturnTypeReferenceBoundNode, includeEliminatedCandidates, isQueryOperatorInvocation, forceExpandedForm, asyncLambdaSubToFunctionMismatch, useSiteInfo) End If End If curriedCandidates.Free() Dim result As OverloadResolutionResult If applicableInstanceCandidateCount = 0 AndAlso Not addedExtensionMethods Then result = ReportOverloadResolutionFailedOrLateBound(candidates, applicableInstanceCandidateCount, lateBindingIsAllowed AndAlso binder.OptionStrict <> OptionStrict.On, asyncLambdaSubToFunctionMismatch) Else result = ResolveOverloading(methodGroup, candidates, arguments, argumentNames, someCandidatesHaveOverloadResolutionPriority, delegateReturnType, lateBindingIsAllowed, binder, asyncLambdaSubToFunctionMismatch, callerInfoOpt, forceExpandedForm, useSiteInfo) End If candidates.Free() Return result End Function Private Shared Function ReportOverloadResolutionFailedOrLateBound(candidates As ArrayBuilder(Of CandidateAnalysisResult), applicableNarrowingCandidateCount As Integer, lateBindingIsAllowed As Boolean, asyncLambdaSubToFunctionMismatch As HashSet(Of BoundExpression)) As OverloadResolutionResult Debug.Assert(applicableNarrowingCandidateCount = 0) Dim isLateBound As Boolean = False If lateBindingIsAllowed Then For Each candidate In candidates If candidate.State = CandidateAnalysisResultState.TypeInferenceFailed Then If candidate.AllFailedInferenceIsDueToObject AndAlso Not candidate.Candidate.IsExtensionMethod Then isLateBound = True Exit For End If End If Next End If Return New OverloadResolutionResult(candidates.ToImmutable, isLateBound, applicableNarrowingCandidateCount > 0, asyncLambdaSubToFunctionMismatch) End Function ''' <summary> ''' Perform overload resolution on the given array of property symbols. ''' </summary> Public Shared Function PropertyInvocationOverloadResolution( propertyGroup As BoundPropertyGroup, arguments As ImmutableArray(Of BoundExpression), argumentNames As ImmutableArray(Of String), binder As Binder, callerInfoOpt As SyntaxNode, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol), Optional includeEliminatedCandidates As Boolean = False ) As OverloadResolutionResult Debug.Assert(propertyGroup.ResultKind = LookupResultKind.Good OrElse propertyGroup.ResultKind = LookupResultKind.Inaccessible) Dim properties As ImmutableArray(Of PropertySymbol) = propertyGroup.Properties ' To simplify code later If arguments.IsDefault Then arguments = ImmutableArray(Of BoundExpression).Empty End If Dim results = ArrayBuilder(Of CandidateAnalysisResult).GetInstance() Dim candidates = ArrayBuilder(Of Candidate).GetInstance(properties.Length - 1) For i As Integer = 0 To properties.Length - 1 Step 1 candidates.Add(New PropertyCandidate(properties(i))) Next Dim asyncLambdaSubToFunctionMismatch As HashSet(Of BoundExpression) = Nothing ' Given the way VB name lookup works, the least derived forms are also among the candidates and are getting filtered out by CombineCandidates. ' Therefore, this simple check gets to them as well without explicitly traversing the overrides hierarchy. Dim someCandidatesHaveOverloadResolutionPriority As Boolean = binder.BindingLocation <> BindingLocation.Attribute AndAlso InternalSyntax.Parser.CheckFeatureAvailability(binder.Compilation.LanguageVersion, InternalSyntax.Feature.OverloadResolutionPriority) AndAlso candidates.Any(Function(candidate) candidate.OverloadResolutionPriority <> 0) CollectOverloadedCandidates(binder, results, candidates, ImmutableArray(Of TypeSymbol).Empty, arguments, argumentNames, someCandidatesHaveOverloadResolutionPriority, Nothing, Nothing, includeEliminatedCandidates, isQueryOperatorInvocation:=False, forceExpandedForm:=False, asyncLambdaSubToFunctionMismatch:=asyncLambdaSubToFunctionMismatch, useSiteInfo:=useSiteInfo) Debug.Assert(asyncLambdaSubToFunctionMismatch Is Nothing) candidates.Free() Dim result = ResolveOverloading(propertyGroup, results, arguments, argumentNames, someCandidatesHaveOverloadResolutionPriority, delegateReturnType:=Nothing, lateBindingIsAllowed:=True, binder:=binder, asyncLambdaSubToFunctionMismatch:=asyncLambdaSubToFunctionMismatch, callerInfoOpt:=callerInfoOpt, forceExpandedForm:=False, useSiteInfo:=useSiteInfo) results.Free() Return result End Function ''' <summary> ''' Given instance method candidates gone through applicability analysis, ''' figure out if we should consider extension methods, if any. ''' </summary> Private Shared Function ShouldConsiderExtensionMethods( candidates As ArrayBuilder(Of CandidateAnalysisResult) ) As Boolean For i As Integer = 0 To candidates.Count - 1 Step 1 Dim candidate = candidates(i) Debug.Assert(Not candidate.Candidate.IsExtensionMethod) If candidate.IgnoreExtensionMethods Then Return False End If Next Return True End Function Private Shared Function ResolveOverloading( methodOrPropertyGroup As BoundMethodOrPropertyGroup, candidates As ArrayBuilder(Of CandidateAnalysisResult), arguments As ImmutableArray(Of BoundExpression), argumentNames As ImmutableArray(Of String), someCandidatesHaveOverloadResolutionPriority As Boolean, delegateReturnType As TypeSymbol, lateBindingIsAllowed As Boolean, binder As Binder, <[In](), Out()> ByRef asyncLambdaSubToFunctionMismatch As HashSet(Of BoundExpression), callerInfoOpt As SyntaxNode, forceExpandedForm As Boolean, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) As OverloadResolutionResult Debug.Assert(argumentNames.IsDefault OrElse argumentNames.Length = arguments.Length) Dim applicableCandidates As Integer Dim resolutionIsLateBound As Boolean = False Dim narrowingCandidatesRemainInTheSet As Boolean = False Dim applicableNarrowingCandidates As Integer = 0 'TODO: Where does this fit? 'Semantics::ResolveOverloading '// See if type inference failed for all candidates and it failed from '// Object. For this scenario, in non-strict mode, treat the call '// as latebound. '§11.8.1 Overloaded Method Resolution '2. Next, eliminate all members from the set that are inaccessible or not applicable to the argument list. ' Note, similar to Dev10 compiler this process will eliminate candidates requiring narrowing conversions ' if strict semantics is used, exception are candidates that require narrowing only from numeric constants. applicableCandidates = EliminateNotApplicableToArguments(methodOrPropertyGroup, candidates, arguments, argumentNames, binder, applicableNarrowingCandidates, asyncLambdaSubToFunctionMismatch, callerInfoOpt, forceExpandedForm, useSiteInfo) If applicableCandidates < 2 Then narrowingCandidatesRemainInTheSet = (applicableNarrowingCandidates > 0) GoTo ResolutionComplete End If If someCandidatesHaveOverloadResolutionPriority Then RemoveLowerPriorityMembers(candidates, applicableCandidates, applicableNarrowingCandidates) If applicableCandidates < 2 Then narrowingCandidatesRemainInTheSet = (applicableNarrowingCandidates > 0) GoTo ResolutionComplete End If ApplyTieBreakingRulesSkippedByCombineCandidates(candidates, applicableCandidates, applicableNarrowingCandidates, arguments.Length, argumentNames, useSiteInfo) If applicableCandidates < 2 Then narrowingCandidatesRemainInTheSet = (applicableNarrowingCandidates > 0) GoTo ResolutionComplete End If End If ' §11.8.1 Overloaded Method Resolution. ' 7.8. If one or more arguments are AddressOf or lambda expressions, and all of the corresponding ' delegate types in M match exactly, but not all do in N, eliminate N from the set. ' 7.9. If one or more arguments are AddressOf or lambda expressions, and all of the corresponding ' delegate types in M are widening conversions, but not all are in N, eliminate N from the set. ' ' The spec implies that this rule is applied to the set of most applicable candidate as one of the tie breaking rules. ' However, doing it there wouldn't have any effect because all candidates in the set of most applicable candidates ' are equally applicable, therefore, have the same types for corresponding parameters. Thus all the candidates ' have exactly the same delegate relaxation level and none would be eliminated. ' Dev10 applies this rule much earlier, even before eliminating narrowing candidates, and it does it across the board. ' I am going to do the same. applicableCandidates = ShadowBasedOnDelegateRelaxation(candidates, applicableNarrowingCandidates) If applicableCandidates < 2 Then narrowingCandidatesRemainInTheSet = (applicableNarrowingCandidates > 0) GoTo ResolutionComplete End If ' §11.8.1 Overloaded Method Resolution. '7.7. If M and N both required type inference to produce type arguments, and M did not ' require determining the dominant type for any of its type arguments (i.e. each the ' type arguments inferred to a single type), but N did, eliminate N from the set. ' Despite what the spec says, this rule is applied after shadowing based on delegate relaxation ' level, however it needs other tie breaking rules applied to equally applicable candidates prior ' to figuring out the minimal inference level to use as the filter. ShadowBasedOnInferenceLevel(candidates, arguments, Not argumentNames.IsDefault, delegateReturnType, binder, applicableCandidates, applicableNarrowingCandidates, useSiteInfo) If applicableCandidates < 2 Then narrowingCandidatesRemainInTheSet = (applicableNarrowingCandidates > 0) GoTo ResolutionComplete End If '3. Next, eliminate all members from the set that require narrowing conversions ' to be applicable to the argument list, except for the case where the argument ' expression type is Object. '4. Next, eliminate all remaining members from the set that require narrowing coercions ' to be applicable to the argument list. If the set is empty, the type containing the ' method group is not an interface, and strict semantics are not being used, the ' invocation target expression is reclassified as a late-bound method access. ' Otherwise, the normal rules apply. If applicableCandidates = applicableNarrowingCandidates Then ' All remaining candidates are narrowing, deal with them. narrowingCandidatesRemainInTheSet = True applicableCandidates = AnalyzeNarrowingCandidates(candidates, arguments, delegateReturnType, lateBindingIsAllowed AndAlso binder.OptionStrict <> OptionStrict.On, binder, resolutionIsLateBound, useSiteInfo) Else If applicableNarrowingCandidates > 0 Then Debug.Assert(applicableNarrowingCandidates < applicableCandidates) applicableCandidates = EliminateNarrowingCandidates(candidates) Debug.Assert(applicableCandidates > 0) If applicableCandidates < 2 Then GoTo ResolutionComplete End If End If '5. Next, if any instance methods remain in the set, ' eliminate all extension methods from the set. ' !!! I don't think we need to do this explicitly. ResolveMethodOverloading doesn't add ' !!! extension methods in the list if we need to remove them here. 'applicableCandidates = EliminateExtensionMethodsInPresenceOfInstanceMethods(candidates) 'If applicableCandidates < 2 Then ' GoTo ResolutionComplete 'End If '6. Next, if, given any two members of the set, M and N, M is more applicable than N ' to the argument list, eliminate N from the set. If more than one member remains ' in the set and the remaining members are not equally applicable to the argument ' list, a compile-time error results. '7. Otherwise, given any two members of the set, M and N, apply the following tie-breaking rules, in order. applicableCandidates = EliminateLessApplicableToTheArguments(candidates, arguments, delegateReturnType, False, ' appliedTieBreakingRules binder, useSiteInfo) End If ResolutionComplete: If Not resolutionIsLateBound AndAlso applicableCandidates = 0 Then Return ReportOverloadResolutionFailedOrLateBound(candidates, applicableCandidates, lateBindingIsAllowed AndAlso binder.OptionStrict <> OptionStrict.On, asyncLambdaSubToFunctionMismatch) End If Return New OverloadResolutionResult(candidates.ToImmutable(), resolutionIsLateBound, narrowingCandidatesRemainInTheSet, asyncLambdaSubToFunctionMismatch) End Function Private Shared ReadOnly s_poolInstance As ObjectPool(Of PooledDictionary(Of NamedTypeSymbol, OneOrMany(Of (Index As Integer, Priority As Integer)))) = PooledDictionary(Of NamedTypeSymbol, OneOrMany(Of (Index As Integer, Priority As Integer))).CreatePool(SymbolEqualityComparer.IgnoreAll) Private Shared Sub RemoveLowerPriorityMembers( candidates As ArrayBuilder(Of CandidateAnalysisResult), ByRef applicableCandidates As Integer, ByRef applicableNarrowingCandidates As Integer ) Dim candidateInfoByDeclaringType As PooledDictionary(Of NamedTypeSymbol, OneOrMany(Of (Index As Integer, Priority As Integer))) = s_poolInstance.Allocate() For i As Integer = 0 To candidates.Count - 1 Step 1 Dim current As CandidateAnalysisResult = candidates(i) If current.State <> CandidateAnalysisResultState.Applicable Then Continue For End If Dim priorityInfo As (Source As NamedTypeSymbol, Priority As Integer) = current.Candidate.GetOverloadResolutionPriorityInfo() Dim siblings As OneOrMany(Of (Index As Integer, Priority As Integer)) = Nothing If candidateInfoByDeclaringType.TryGetValue(priorityInfo.Source, siblings) Then candidateInfoByDeclaringType(priorityInfo.Source) = siblings.Add((i, priorityInfo.Priority)) Else candidateInfoByDeclaringType.Add(priorityInfo.Source, OneOrMany.Create((i, priorityInfo.Priority))) End If Next For Each siblings In candidateInfoByDeclaringType.Values If siblings.Count = 1 Then Continue For End If Dim maxPriority = Integer.MinValue For Each info In siblings Dim candidate = candidates(info.Index) If candidate.RequiresNarrowingConversion OrElse candidate.MaxDelegateRelaxationLevel = ConversionKind.DelegateRelaxationLevelNarrowing Then Continue For End If If maxPriority < info.Priority Then maxPriority = info.Priority End If Next If maxPriority = Integer.MinValue Then Continue For End If For Each info In siblings If maxPriority > info.Priority Then Dim toDeprioritize = candidates(info.Index) applicableCandidates -= 1 If toDeprioritize.RequiresNarrowingConversion Then applicableNarrowingCandidates -= 1 End If toDeprioritize.State = CandidateAnalysisResultState.LessApplicable candidates(info.Index) = toDeprioritize End If Next Next candidateInfoByDeclaringType.Free() End Sub Private Shared Sub ApplyTieBreakingRulesSkippedByCombineCandidates( candidates As ArrayBuilder(Of CandidateAnalysisResult), ByRef applicableCandidates As Integer, ByRef applicableNarrowingCandidates As Integer, argumentCount As Integer, argumentNames As ImmutableArray(Of String), <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) For i As Integer = 0 To candidates.Count - 1 Step 1 Dim existingCandidate As CandidateAnalysisResult = candidates(i) ' Skip over some eliminated candidates, which we will be unable to match signature against. If existingCandidate.State = CandidateAnalysisResultState.ArgumentCountMismatch OrElse existingCandidate.State = CandidateAnalysisResultState.BadGenericArity OrElse existingCandidate.State = CandidateAnalysisResultState.Ambiguous OrElse existingCandidate.State = CandidateAnalysisResultState.TypeInferenceFailed OrElse existingCandidate.SomeInferenceFailed OrElse existingCandidate.State = CandidateAnalysisResultState.HasUseSiteError OrElse existingCandidate.State = CandidateAnalysisResultState.HasUnsupportedMetadata OrElse existingCandidate.State = CandidateAnalysisResultState.LessApplicable OrElse existingCandidate.State = CandidateAnalysisResultState.Shadowed Then Continue For End If For j As Integer = i + 1 To candidates.Count - 1 Step 1 Dim newCandidate As CandidateAnalysisResult = candidates(j) If newCandidate.State <> CandidateAnalysisResultState.Applicable Then Continue For End If ' Candidate can't hide another form of itself If existingCandidate.Candidate Is newCandidate.Candidate Then Continue For End If Dim existingWins As Boolean = False Dim newWins As Boolean = False If ApplyTieBreakingRulesSkippedByCombineCandidates(existingCandidate, newCandidate, argumentCount, argumentNames, useSiteInfo, existingWins, newWins) Then Debug.Assert(existingWins Xor newWins) ' Both cannot win! Dim lost As Integer = If(existingWins, j, i) Dim toShadow = candidates(lost) If toShadow.State = CandidateAnalysisResultState.Applicable Then applicableCandidates -= 1 If toShadow.RequiresNarrowingConversion Then applicableNarrowingCandidates -= 1 End If End If toShadow.State = CandidateAnalysisResultState.Shadowed candidates(lost) = toShadow If lost = i Then Exit For End If End If Next Next End Sub Private Shared Function ApplyTieBreakingRulesSkippedByCombineCandidates( existingCandidate As CandidateAnalysisResult, newCandidate As CandidateAnalysisResult, argumentCount As Integer, argumentNames As ImmutableArray(Of String), <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol), ByRef existingWins As Boolean, ByRef newWins As Boolean ) As Boolean Debug.Assert(newCandidate.State = CandidateAnalysisResultState.Applicable) Dim operatorResolution As Boolean = newCandidate.Candidate.IsOperator Debug.Assert(newCandidate.Candidate.ParameterCount >= argumentCount OrElse newCandidate.IsExpandedParamArrayForm) Debug.Assert(argumentNames.IsDefault OrElse argumentNames.Length > 0) Debug.Assert(Not operatorResolution OrElse argumentNames.IsDefault) ' It looks like the following code is applying some tie-breaking rules from section 7 of ' §11.8.1 Overloaded Method Resolution, but not all of them and even skips ParamArrays tie-breaking ' rule in some scenarios. I couldn't find an explanation of this behavior in the spec and ' simply tried to keep this code close to Dev10. ' Spec says that the tie-breaking rules should be applied only for members equally applicable to the argument list. ' [§11.8.1.1 Applicability] defines equally applicable members as follows: ' A member M is considered equally applicable as N if ' 1) their signatures are the same or ' 2) if each parameter type in M is the same as the corresponding parameter type in N. ' We can always check if signature is the same, but we cannot check the second condition in presence ' of named arguments because for them we don't know yet which parameter in M corresponds to which ' parameter in N. Debug.Assert(existingCandidate.Candidate.ParameterCount >= argumentCount OrElse existingCandidate.IsExpandedParamArrayForm) ' Check if the shadowing below can be applied in theory If Not existingCandidate.IsExpandedParamArrayForm AndAlso Not newCandidate.IsExpandedParamArrayForm AndAlso Not argumentNames.IsDefault AndAlso (existingCandidate.Candidate.IsExtensionMethod OrElse newCandidate.Candidate.IsExtensionMethod) Then Return False End If If argumentNames.IsDefault Then If Not CombineCandidatesCompareVirtualSignature(newCandidate, existingCandidate, argumentCount) Then ' Signatures are different, shadowing rules do not apply Return False End If Else Debug.Assert(Not operatorResolution) End If Dim signatureMatch As Boolean ' Compare complete signature, with no regard to arguments If existingCandidate.Candidate.ParameterCount <> newCandidate.Candidate.ParameterCount Then Debug.Assert(Not operatorResolution) signatureMatch = False ElseIf operatorResolution Then Debug.Assert(argumentNames.IsDefault) ' We matched the virtual signature above Debug.Assert(argumentCount = existingCandidate.Candidate.ParameterCount) signatureMatch = True ' Not lifted operators are preferred over lifted. If ShadowBasedOnLiftedState(existingCandidate, newCandidate, existingWins, newWins) Then Return True End If Else signatureMatch = CombineCandidatesCompareDeclaredSignature(newCandidate, existingCandidate) End If If Not argumentNames.IsDefault AndAlso Not signatureMatch Then ' Signatures are different, shadowing rules do not apply Return False End If If Not signatureMatch Then Debug.Assert(argumentNames.IsDefault) ' We matched the virtual signature above ' If we have gotten to this point it means that the 2 procedures have equal specificity, ' but signatures that do not match exactly (after generic substitution). This ' implies that we are dealing with differences in shape due to param arrays ' or optional arguments. ' So we look and see if one procedure maps fewer arguments to the ' param array than the other. The one using more, is then shadowed by the one using less. '• If M has fewer parameters from an expanded paramarray than N, eliminate N from the set. If ShadowBasedOnParamArrayUsage(existingCandidate, newCandidate, existingWins, newWins) Then Return True End If Else ' The signatures of the two methods match (after generic parameter substitution). ' This means that param array shadowing doesn't come into play. ' !!! Why? Where is this mentioned in the spec? End If Debug.Assert(argumentNames.IsDefault OrElse signatureMatch) ' In presence of named arguments, the following shadowing rules ' cannot be applied if any candidate is extension method because ' full signature match doesn't guarantee equal applicability (in presence of named arguments) ' and instance methods hide by signature regardless applicability rules do not apply to extension methods. If argumentNames.IsDefault OrElse Not (existingCandidate.Candidate.IsExtensionMethod OrElse newCandidate.Candidate.IsExtensionMethod) Then '7.1. If M is defined in a more derived type than N, eliminate N from the set. ' This rule also applies to the types that extension methods are defined on. '7.2. If M and N are extension methods and the target type of M is a class or ' structure and the target type of N is an interface, eliminate N from the set. If (Not signatureMatch OrElse existingCandidate.Candidate.IsExtensionMethod OrElse newCandidate.Candidate.IsExtensionMethod) AndAlso ShadowBasedOnReceiverType(existingCandidate, newCandidate, existingWins, newWins, useSiteInfo) Then Return True End If '7.3. If M and N are extension methods and the target type of M has fewer type ' parameters than the target type of N, eliminate N from the set. ' !!! Note that spec talks about "fewer type parameters", but it is not really about count. ' !!! It is about one refers to a type parameter and the other one doesn't. If ShadowBasedOnExtensionMethodTargetTypeGenericity(existingCandidate, newCandidate, existingWins, newWins) Then Return True End If End If Return False End Function Private Shared Function EliminateNarrowingCandidates( candidates As ArrayBuilder(Of CandidateAnalysisResult) ) As Integer Dim applicableCandidates As Integer = 0 For i As Integer = 0 To candidates.Count - 1 Step 1 Dim current As CandidateAnalysisResult = candidates(i) If current.State = CandidateAnalysisResultState.Applicable Then If current.RequiresNarrowingConversion Then current.State = CandidateAnalysisResultState.RequiresNarrowing candidates(i) = current Else applicableCandidates += 1 End If End If Next Return applicableCandidates End Function ''' <summary> ''' §11.8.1 Overloaded Method Resolution ''' 6. Next, if, given any two members of the set, M and N, M is more applicable than N ''' to the argument list, eliminate N from the set. If more than one member remains ''' in the set and the remaining members are not equally applicable to the argument ''' list, a compile-time error results. ''' 7. Otherwise, given any two members of the set, M and N, apply the following tie-breaking rules, in order. ''' ''' Returns amount of applicable candidates left. ''' ''' Note that less applicable candidates are going to be eliminated if and only if there are most applicable ''' candidates. ''' </summary> Private Shared Function EliminateLessApplicableToTheArguments( candidates As ArrayBuilder(Of CandidateAnalysisResult), arguments As ImmutableArray(Of BoundExpression), delegateReturnType As TypeSymbol, appliedTieBreakingRules As Boolean, binder As Binder, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol), Optional mostApplicableMustNarrowOnlyFromNumericConstants As Boolean = False ) As Integer Dim applicableCandidates As Integer Dim indexesOfEqualMostApplicableCandidates As ArrayBuilder(Of Integer) = ArrayBuilder(Of Integer).GetInstance() If FastFindMostApplicableCandidates(candidates, arguments, indexesOfEqualMostApplicableCandidates, binder, useSiteInfo) AndAlso (mostApplicableMustNarrowOnlyFromNumericConstants = False OrElse candidates(indexesOfEqualMostApplicableCandidates(0)).RequiresNarrowingNotFromNumericConstant = False OrElse indexesOfEqualMostApplicableCandidates.Count = CountApplicableCandidates(candidates)) Then ' We have most applicable candidates. ' Mark those that lost applicability comparison. ' Applicable candidates with indexes before the first value in indexesOfEqualMostApplicableCandidates, ' after the last value in indexesOfEqualMostApplicableCandidates and in between consecutive values in ' indexesOfEqualMostApplicableCandidates are less applicable. Debug.Assert(indexesOfEqualMostApplicableCandidates.Count > 0) Dim nextMostApplicable As Integer = 0 ' and index into indexesOfEqualMostApplicableCandidates Dim indexOfNextMostApplicable As Integer = indexesOfEqualMostApplicableCandidates(nextMostApplicable) For i As Integer = 0 To candidates.Count - 1 Step 1 If i = indexOfNextMostApplicable Then nextMostApplicable += 1 If nextMostApplicable < indexesOfEqualMostApplicableCandidates.Count Then indexOfNextMostApplicable = indexesOfEqualMostApplicableCandidates(nextMostApplicable) Else indexOfNextMostApplicable = candidates.Count End If Continue For End If Dim contender As CandidateAnalysisResult = candidates(i) If contender.State <> CandidateAnalysisResultState.Applicable Then Continue For End If contender.State = CandidateAnalysisResultState.LessApplicable candidates(i) = contender Next ' Apply tie-breaking rules If Not appliedTieBreakingRules Then applicableCandidates = ApplyTieBreakingRules(candidates, indexesOfEqualMostApplicableCandidates, arguments, delegateReturnType, binder, useSiteInfo) Else applicableCandidates = indexesOfEqualMostApplicableCandidates.Count End If ElseIf Not appliedTieBreakingRules Then ' Overload resolution failed, we couldn't find most applicable candidates. ' We still need to apply shadowing rules to the sets of equally applicable candidates, ' this will provide better error reporting experience. As we are doing this, we will redo ' applicability comparisons that we've done earlier in FastFindMostApplicableCandidates, but we are willing to ' pay the price for erroneous code. applicableCandidates = ApplyTieBreakingRulesToEquallyApplicableCandidates(candidates, arguments, delegateReturnType, binder, useSiteInfo) Else applicableCandidates = CountApplicableCandidates(candidates) End If indexesOfEqualMostApplicableCandidates.Free() Return applicableCandidates End Function Private Shared Function CountApplicableCandidates(candidates As ArrayBuilder(Of CandidateAnalysisResult)) As Integer Dim applicableCandidates As Integer = 0 For i As Integer = 0 To candidates.Count - 1 Step 1 If candidates(i).State <> CandidateAnalysisResultState.Applicable Then Continue For End If applicableCandidates += 1 Next Return applicableCandidates End Function ''' <summary> ''' Returns amount of applicable candidates left. ''' </summary> Private Shared Function ApplyTieBreakingRulesToEquallyApplicableCandidates( candidates As ArrayBuilder(Of CandidateAnalysisResult), arguments As ImmutableArray(Of BoundExpression), delegateReturnType As TypeSymbol, binder As Binder, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) As Integer ' First, let's break all remaining candidates into buckets of equally applicable candidates Dim buckets = GroupEquallyApplicableCandidates(candidates, arguments, binder) Debug.Assert(buckets.Count > 0) Dim applicableCandidates As Integer = 0 ' Apply tie-breaking rules For i As Integer = 0 To buckets.Count - 1 Step 1 applicableCandidates += ApplyTieBreakingRules(candidates, buckets(i), arguments, delegateReturnType, binder, useSiteInfo) Next ' Release memory we no longer need. For i As Integer = 0 To buckets.Count - 1 Step 1 buckets(i).Free() Next buckets.Free() Return applicableCandidates End Function ''' <summary> ''' Returns True if there are most applicable candidates. ''' ''' indexesOfMostApplicableCandidates will contain indexes of equally applicable candidates, which are most applicable ''' by comparison to the other (non-equal) candidates. The indexes will be in ascending order. ''' </summary> Private Shared Function FastFindMostApplicableCandidates( candidates As ArrayBuilder(Of CandidateAnalysisResult), arguments As ImmutableArray(Of BoundExpression), indexesOfMostApplicableCandidates As ArrayBuilder(Of Integer), binder As Binder, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) As Boolean Dim mightBeTheMostApplicableIndex As Integer = -1 Dim mightBeTheMostApplicable As CandidateAnalysisResult = Nothing indexesOfMostApplicableCandidates.Clear() ' Use linear complexity algorithm to find the first most applicable candidate. ' We are saying "the first" because there could be a number of candidates equally applicable ' by comparison to the one we find, their indexes are collected in indexesOfMostApplicableCandidates. For i As Integer = 0 To candidates.Count - 1 Step 1 Dim contender As CandidateAnalysisResult = candidates(i) If contender.State <> CandidateAnalysisResultState.Applicable Then Continue For End If If mightBeTheMostApplicableIndex = -1 Then mightBeTheMostApplicableIndex = i mightBeTheMostApplicable = contender indexesOfMostApplicableCandidates.Add(i) Else Dim cmp As ApplicabilityComparisonResult = CompareApplicabilityToTheArguments(mightBeTheMostApplicable, contender, arguments, binder, useSiteInfo) If cmp = ApplicabilityComparisonResult.RightIsMoreApplicable Then mightBeTheMostApplicableIndex = i mightBeTheMostApplicable = contender indexesOfMostApplicableCandidates.Clear() indexesOfMostApplicableCandidates.Add(i) ElseIf cmp = ApplicabilityComparisonResult.Undefined Then mightBeTheMostApplicableIndex = -1 indexesOfMostApplicableCandidates.Clear() ElseIf cmp = ApplicabilityComparisonResult.EquallyApplicable Then indexesOfMostApplicableCandidates.Add(i) Else Debug.Assert(cmp = ApplicabilityComparisonResult.LeftIsMoreApplicable) End If End If Next For i As Integer = 0 To mightBeTheMostApplicableIndex - 1 Step 1 Dim contender As CandidateAnalysisResult = candidates(i) If contender.State <> CandidateAnalysisResultState.Applicable Then Continue For End If Dim cmp As ApplicabilityComparisonResult = CompareApplicabilityToTheArguments(mightBeTheMostApplicable, contender, arguments, binder, useSiteInfo) If cmp = ApplicabilityComparisonResult.RightIsMoreApplicable OrElse cmp = ApplicabilityComparisonResult.Undefined OrElse cmp = ApplicabilityComparisonResult.EquallyApplicable Then ' We do this for equal applicability too because this contender was dropped during the first loop, so, ' if we continue, the mightBeTheMostApplicable candidate will be definitely dropped too. mightBeTheMostApplicableIndex = -1 Exit For Else Debug.Assert(cmp = ApplicabilityComparisonResult.LeftIsMoreApplicable) End If Next Return (mightBeTheMostApplicableIndex > -1) End Function ''' <summary> ''' §11.8.1 Overloaded Method Resolution ''' 7. Otherwise, given any two members of the set, M and N, apply the following tie-breaking rules, in order. ''' </summary> Private Shared Function ApplyTieBreakingRules( candidates As ArrayBuilder(Of CandidateAnalysisResult), bucket As ArrayBuilder(Of Integer), arguments As ImmutableArray(Of BoundExpression), delegateReturnType As TypeSymbol, binder As Binder, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) As Integer Dim leftWins As Boolean Dim rightWins As Boolean Dim applicableCandidates As Integer = bucket.Count For i = 0 To bucket.Count - 1 Step 1 Dim left = candidates(bucket(i)) If left.State <> CandidateAnalysisResultState.Applicable Then Continue For End If For j = i + 1 To bucket.Count - 1 Step 1 Dim right = candidates(bucket(j)) If right.State <> CandidateAnalysisResultState.Applicable Then Continue For End If If ShadowBasedOnTieBreakingRules(left, right, arguments, delegateReturnType, leftWins, rightWins, binder, useSiteInfo) Then Debug.Assert(Not (leftWins AndAlso rightWins)) If leftWins Then right.State = CandidateAnalysisResultState.Shadowed candidates(bucket(j)) = right applicableCandidates -= 1 Else Debug.Assert(rightWins) left.State = CandidateAnalysisResultState.Shadowed candidates(bucket(i)) = left applicableCandidates -= 1 Exit For End If End If Next Next Debug.Assert(applicableCandidates >= 0) Return applicableCandidates End Function ''' <summary> ''' §11.8.1 Overloaded Method Resolution ''' 7. Otherwise, given any two members of the set, M and N, apply the following tie-breaking rules, in order. ''' </summary> Private Shared Function ShadowBasedOnTieBreakingRules( left As CandidateAnalysisResult, right As CandidateAnalysisResult, arguments As ImmutableArray(Of BoundExpression), delegateReturnType As TypeSymbol, ByRef leftWins As Boolean, ByRef rightWins As Boolean, binder As Binder, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) As Boolean ' Let's apply various shadowing and tie-breaking rules ' from section 7 of §11.8.1 Overloaded Method Resolution. leftWins = False rightWins = False '• If M has fewer parameters from an expanded paramarray than N, eliminate N from the set. If ShadowBasedOnParamArrayUsage(left, right, leftWins, rightWins) Then Return True End If '7.1. If M is defined in a more derived type than N, eliminate N from the set. ' This rule also applies to the types that extension methods are defined on. '7.2. If M and N are extension methods and the target type of M is a class or ' structure and the target type of N is an interface, eliminate N from the set. If ShadowBasedOnReceiverType(left, right, leftWins, rightWins, useSiteInfo) Then Return True ' I believe we can get here only in presence of named arguments and optional parameters. Otherwise, CombineCandidates takes care of this shadowing. End If '7.3. If M and N are extension methods and the target type of M has fewer type ' parameters than the target type of N, eliminate N from the set. ' !!! Note that spec talks about "fewer type parameters", but it is not really about count. ' !!! It is about one refers to a type parameter and the other one doesn't. If ShadowBasedOnExtensionMethodTargetTypeGenericity(left, right, leftWins, rightWins) Then Return True ' I believe we can get here only in presence of named arguments and optional parameters. Otherwise, CombineCandidates takes care of this shadowing. End If '7.4. If M is less generic than N, eliminate N from the set. If ShadowBasedOnGenericity(left, right, leftWins, rightWins, arguments, binder) Then Return True End If '7.5. If M is not an extension method and N is, eliminate N from the set. '7.6. If M and N are extension methods and M was found before N, eliminate N from the set. If ShadowBasedOnExtensionVsInstanceAndPrecedence(left, right, leftWins, rightWins) Then Return True End If '7.7. If M and N both required type inference to produce type arguments, and M did not ' require determining the dominant type for any of its type arguments (i.e. each the ' type arguments inferred to a single type), but N did, eliminate N from the set. ' The spec is incorrect, this shadowing doesn't belong here, it is applied across the board ' after these tie breaking rules. For more information, see comment in ResolveOverloading. '7.8. If one or more arguments are AddressOf or lambda expressions, and all of the corresponding delegate types in M match exactly, but not all do in N, eliminate N from the set. '7.9. If one or more arguments are AddressOf or lambda expressions, and all of the corresponding delegate types in M are widening conversions, but not all are in N, eliminate N from the set. ' The spec is incorrect, this shadowing doesn't belong here, it is applied much earlier. ' For more information, see comment in ResolveOverloading. ' 7.9. If M did not use any optional parameter defaults in place of explicit ' arguments, but N did, then eliminate N from the set. ' ' !!!WARNING!!! The index (7.9) is based on "VB11 spec [draft 3]" version of documentation rather ' than Dev10 documentation. If ShadowBasedOnOptionalParametersDefaultsUsed(left, right, leftWins, rightWins) Then Return True End If '7.10. If the overload resolution is being done to resolve the target of a delegate-creation expression from an AddressOf expression and M is a function, while N is a subroutine, eliminate N from the set. If ShadowBasedOnSubOrFunction(left, right, delegateReturnType, leftWins, rightWins) Then Return True End If ' 7.10. Before type arguments have been substituted, if M has greater depth of ' genericity (Section 11.8.1.3) than N, then eliminate N from the set. ' ' !!!WARNING!!! The index (7.10) is based on "VB11 spec [draft 3]" version of documentation ' rather than Dev10 documentation. ' ' NOTE: Dev11 puts this analysis in a second phase with the first phase ' performing analysis of { $11.8.1:6 + 7.9/7.10/7.11/7.8 }, see comments in ' OverloadResolution.cpp: bool Semantics::AreProceduresEquallySpecific(...) ' ' Placing this analysis here seems to be more natural than ' matching Dev11 implementation If ShadowBasedOnDepthOfGenericity(left, right, leftWins, rightWins, arguments, binder) Then Return True End If Return False End Function ''' <summary> ''' Implements shadowing based on ''' §11.8.1 Overloaded Method Resolution. ''' 7.10. If the overload resolution is being done to resolve the target of a ''' delegate-creation expression from an AddressOf expression and M is a ''' function, while N is a subroutine, eliminate N from the set. ''' </summary> Private Shared Function ShadowBasedOnSubOrFunction( left As CandidateAnalysisResult, right As CandidateAnalysisResult, delegateReturnType As TypeSymbol, ByRef leftWins As Boolean, ByRef rightWins As Boolean ) As Boolean ' !!! Actually, the spec isn't accurate here. If the target delegate is a Sub, we prefer a Sub. !!! ' !!! If the target delegate is a Function, we prefer a Function. !!! If delegateReturnType Is Nothing Then Return False End If Dim leftReturnsVoid As Boolean = left.Candidate.ReturnType.IsVoidType() Dim rightReturnsVoid As Boolean = right.Candidate.ReturnType.IsVoidType() If leftReturnsVoid = rightReturnsVoid Then Return False End If If delegateReturnType.IsVoidType() = leftReturnsVoid Then leftWins = True Return True End If Debug.Assert(delegateReturnType.IsVoidType() = rightReturnsVoid) rightWins = True Return True End Function ''' <summary> ''' Implements shadowing based on ''' §11.8.1 Overloaded Method Resolution. ''' 7.8. If one or more arguments are AddressOf or lambda expressions, and all of the corresponding ''' delegate types in M match exactly, but not all do in N, eliminate N from the set. ''' 7.9. If one or more arguments are AddressOf or lambda expressions, and all of the corresponding ''' delegate types in M are widening conversions, but not all are in N, eliminate N from the set. ''' </summary> Private Shared Function ShadowBasedOnDelegateRelaxation( candidates As ArrayBuilder(Of CandidateAnalysisResult), ByRef applicableNarrowingCandidates As Integer ) As Integer ' Find the minimal MaxDelegateRelaxationLevel Dim minMaxRelaxation As ConversionKind = ConversionKind.DelegateRelaxationLevelInvalid For i As Integer = 0 To candidates.Count - 1 Step 1 Dim current As CandidateAnalysisResult = candidates(i) If current.State = CandidateAnalysisResultState.Applicable Then Dim relaxation As ConversionKind = current.MaxDelegateRelaxationLevel If relaxation < minMaxRelaxation Then minMaxRelaxation = relaxation End If End If Next ' Now eliminate all candidates with relaxation level bigger than the minimal. Dim applicableCandidates As Integer = 0 applicableNarrowingCandidates = 0 For i As Integer = 0 To candidates.Count - 1 Step 1 Dim current As CandidateAnalysisResult = candidates(i) If current.State <> CandidateAnalysisResultState.Applicable Then Continue For End If Dim relaxation As ConversionKind = current.MaxDelegateRelaxationLevel If relaxation > minMaxRelaxation Then current.State = CandidateAnalysisResultState.Shadowed candidates(i) = current Else applicableCandidates += 1 If current.RequiresNarrowingConversion Then applicableNarrowingCandidates += 1 End If End If Next Return applicableCandidates End Function ''' <summary> ''' Implements shadowing based on ''' §11.8.1 Overloaded Method Resolution. ''' 7.9. If M did not use any optional parameter defaults in place of explicit ''' arguments, but N did, then eliminate N from the set. ''' ''' !!!WARNING!!! The index (7.9) is based on "VB11 spec [draft 3]" version of documentation rather ''' than Dev10 documentation. ''' TODO: Update indexes of other overload method resolution rules ''' </summary> Private Shared Function ShadowBasedOnOptionalParametersDefaultsUsed( left As CandidateAnalysisResult, right As CandidateAnalysisResult, ByRef leftWins As Boolean, ByRef rightWins As Boolean ) As Boolean Dim leftUsesOptionalParameterDefaults As Boolean = left.UsedOptionalParameterDefaultValue If leftUsesOptionalParameterDefaults = right.UsedOptionalParameterDefaultValue Then Return False ' No winner End If If Not leftUsesOptionalParameterDefaults Then leftWins = True Else rightWins = True End If Return True End Function ''' <summary> ''' Implements shadowing based on ''' §11.8.1 Overloaded Method Resolution. ''' 7.7. If M and N both required type inference to produce type arguments, and M did not ''' require determining the dominant type for any of its type arguments (i.e. each the ''' type arguments inferred to a single type), but N did, eliminate N from the set. ''' </summary> Private Shared Sub ShadowBasedOnInferenceLevel( candidates As ArrayBuilder(Of CandidateAnalysisResult), arguments As ImmutableArray(Of BoundExpression), haveNamedArguments As Boolean, delegateReturnType As TypeSymbol, binder As Binder, ByRef applicableCandidates As Integer, ByRef applicableNarrowingCandidates As Integer, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) Debug.Assert(Not haveNamedArguments OrElse Not candidates(0).Candidate.IsOperator) ' See if there are candidates with different InferenceLevel Dim haveDifferentInferenceLevel As Boolean = False Dim theOnlyInferenceLevel As TypeArgumentInference.InferenceLevel = CType(Byte.MaxValue, TypeArgumentInference.InferenceLevel) For i As Integer = 0 To candidates.Count - 1 Step 1 Dim current As CandidateAnalysisResult = candidates(i) If current.State = CandidateAnalysisResultState.Applicable Then Dim inferenceLevel As TypeArgumentInference.InferenceLevel = current.InferenceLevel If theOnlyInferenceLevel = Byte.MaxValue Then theOnlyInferenceLevel = inferenceLevel ElseIf inferenceLevel <> theOnlyInferenceLevel Then haveDifferentInferenceLevel = True Exit For End If End If Next If Not haveDifferentInferenceLevel Then ' Nothing to do. Return End If ' Native compiler used to have a bug where CombineCandidates was applying shadowing in presence of named arguments ' before figuring out whether candidates are applicable. We fixed that. However, in cases when candidates were applicable ' after all, that shadowing had impact on the shadowing based on the inference level by affecting minimal inference level. ' To compensate, we will perform the CombineCandidates-style shadowing here. Note that we cannot simply call ' ApplyTieBreakingRulesToEquallyApplicableCandidates to do this because shadowing performed by CombineCandidates is more ' constrained. If haveNamedArguments Then Debug.Assert(Not candidates(0).Candidate.IsOperator) Dim indexesOfApplicableCandidates = ArrayBuilder(Of Integer).GetInstance(applicableCandidates) For i As Integer = 0 To candidates.Count - 1 Step 1 If candidates(i).State = CandidateAnalysisResultState.Applicable Then indexesOfApplicableCandidates.Add(i) End If Next Debug.Assert(indexesOfApplicableCandidates.Count = applicableCandidates) ' Sort indexes by inference level indexesOfApplicableCandidates.Sort(New InferenceLevelComparer(candidates)) #If DEBUG Then Dim level As TypeArgumentInference.InferenceLevel = TypeArgumentInference.InferenceLevel.None For Each index As Integer In indexesOfApplicableCandidates Debug.Assert(level <= candidates(index).InferenceLevel) level = candidates(index).InferenceLevel Next #End If ' In order of sorted indexes, apply constrained shadowing rules looking for the first one survived. ' This will be sufficient to calculate "correct" minimal inference level. We don't have to apply ' shadowing to each pair of candidates. For i As Integer = 0 To indexesOfApplicableCandidates.Count - 2 Dim left As CandidateAnalysisResult = candidates(indexesOfApplicableCandidates(i)) If left.State <> CandidateAnalysisResultState.Applicable Then Continue For End If For j As Integer = i + 1 To indexesOfApplicableCandidates.Count - 1 Dim right As CandidateAnalysisResult = candidates(indexesOfApplicableCandidates(j)) If right.State <> CandidateAnalysisResultState.Applicable Then Continue For End If ' Shadowing is applied only to candidates that have the same types for corresponding parameters ' in virtual signatures Dim equallyApplicable As Boolean = True For k = 0 To arguments.Length - 1 Step 1 Dim leftParamType As TypeSymbol = GetParameterTypeFromVirtualSignature(left, left.ArgsToParamsOpt(k)) Dim rightParamType As TypeSymbol = GetParameterTypeFromVirtualSignature(right, right.ArgsToParamsOpt(k)) If Not leftParamType.IsSameTypeIgnoringAll(rightParamType) Then ' Signatures are different, shadowing rules do not apply equallyApplicable = False Exit For End If Next If Not equallyApplicable Then Continue For End If Dim signatureMatch As Boolean = True ' Compare complete signature, with no regard to arguments If left.Candidate.ParameterCount <> right.Candidate.ParameterCount Then signatureMatch = False Else For k As Integer = 0 To left.Candidate.ParameterCount - 1 Step 1 Dim leftType As TypeSymbol = left.Candidate.Parameters(k).Type Dim rightType As TypeSymbol = right.Candidate.Parameters(k).Type If Not leftType.IsSameTypeIgnoringAll(rightType) Then signatureMatch = False Exit For End If Next End If Dim leftWins As Boolean = False Dim rightWins As Boolean = False If (Not signatureMatch AndAlso ShadowBasedOnParamArrayUsage(left, right, leftWins, rightWins)) OrElse ShadowBasedOnReceiverType(left, right, leftWins, rightWins, useSiteInfo) OrElse ShadowBasedOnExtensionMethodTargetTypeGenericity(left, right, leftWins, rightWins) Then Debug.Assert(leftWins Xor rightWins) If leftWins Then right.State = CandidateAnalysisResultState.Shadowed candidates(indexesOfApplicableCandidates(j)) = right ElseIf rightWins Then left.State = CandidateAnalysisResultState.Shadowed candidates(indexesOfApplicableCandidates(i)) = left Exit For ' advance to the next left End If End If Next If left.State = CandidateAnalysisResultState.Applicable Then ' left has survived Exit For End If Next indexesOfApplicableCandidates.Free() End If ' Find the minimal InferenceLevel Dim minInferenceLevel = TypeArgumentInference.InferenceLevel.Invalid For i As Integer = 0 To candidates.Count - 1 Step 1 Dim current As CandidateAnalysisResult = candidates(i) If current.State = CandidateAnalysisResultState.Applicable Then Dim inferenceLevel As TypeArgumentInference.InferenceLevel = current.InferenceLevel If inferenceLevel < minInferenceLevel Then minInferenceLevel = inferenceLevel End If End If Next ' Now eliminate all candidates with inference level bigger than the minimal. applicableCandidates = 0 applicableNarrowingCandidates = 0 For i As Integer = 0 To candidates.Count - 1 Step 1 Dim current As CandidateAnalysisResult = candidates(i) If current.State <> CandidateAnalysisResultState.Applicable Then Continue For End If Dim inferenceLevel As TypeArgumentInference.InferenceLevel = current.InferenceLevel If inferenceLevel > minInferenceLevel Then current.State = CandidateAnalysisResultState.Shadowed candidates(i) = current Else applicableCandidates += 1 If current.RequiresNarrowingConversion Then applicableNarrowingCandidates += 1 End If End If Next ' Done. End Sub Private Class InferenceLevelComparer Implements IComparer(Of Integer) Private ReadOnly _candidates As ArrayBuilder(Of CandidateAnalysisResult) Public Sub New(candidates As ArrayBuilder(Of CandidateAnalysisResult)) _candidates = candidates End Sub Public Function Compare(indexX As Integer, indexY As Integer) As Integer Implements IComparer(Of Integer).Compare Return CInt(_candidates(indexX).InferenceLevel).CompareTo(_candidates(indexY).InferenceLevel) End Function End Class ''' <summary> ''' §11.8.1.1 Applicability ''' </summary> Private Shared Function CompareApplicabilityToTheArguments( ByRef left As CandidateAnalysisResult, ByRef right As CandidateAnalysisResult, arguments As ImmutableArray(Of BoundExpression), binder As Binder, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) As ApplicabilityComparisonResult ' §11.8.1.1 Applicability 'A member M is considered more applicable than N if their signatures are different and at least one 'parameter type in M is more applicable than a parameter type in N, and no parameter type in N is more 'applicable than a parameter type in M. Dim equallyApplicable As Boolean = True Dim leftHasMoreApplicableParameterType As Boolean = False Dim rightHasMoreApplicableParameterType As Boolean = False Dim leftParamIndex As Integer = 0 Dim rightParamIndex As Integer = 0 For i = 0 To arguments.Length - 1 Step 1 Dim leftParamType As TypeSymbol Debug.Assert(left.ArgsToParamsOpt.IsDefault = right.ArgsToParamsOpt.IsDefault) If left.ArgsToParamsOpt.IsDefault Then leftParamType = GetParameterTypeFromVirtualSignature(left, leftParamIndex) AdvanceParameterInVirtualSignature(left, leftParamIndex) Else leftParamType = GetParameterTypeFromVirtualSignature(left, left.ArgsToParamsOpt(i)) End If Dim rightParamType As TypeSymbol If right.ArgsToParamsOpt.IsDefault Then rightParamType = GetParameterTypeFromVirtualSignature(right, rightParamIndex) AdvanceParameterInVirtualSignature(right, rightParamIndex) Else rightParamType = GetParameterTypeFromVirtualSignature(right, right.ArgsToParamsOpt(i)) End If ' Parameters matching omitted arguments do not participate. If arguments(i).Kind = BoundKind.OmittedArgument Then Continue For End If Dim cmp = CompareParameterTypeApplicability(leftParamType, rightParamType, arguments(i), binder, useSiteInfo) If cmp = ApplicabilityComparisonResult.LeftIsMoreApplicable Then leftHasMoreApplicableParameterType = True If rightHasMoreApplicableParameterType Then Return ApplicabilityComparisonResult.Undefined ' Neither is more applicable End If equallyApplicable = False ElseIf cmp = ApplicabilityComparisonResult.RightIsMoreApplicable Then rightHasMoreApplicableParameterType = True If leftHasMoreApplicableParameterType Then Return ApplicabilityComparisonResult.Undefined ' Neither is more applicable End If equallyApplicable = False ElseIf cmp = ApplicabilityComparisonResult.Undefined Then equallyApplicable = False Else Debug.Assert(cmp = ApplicabilityComparisonResult.EquallyApplicable) End If Next Debug.Assert(Not (leftHasMoreApplicableParameterType AndAlso rightHasMoreApplicableParameterType)) If leftHasMoreApplicableParameterType Then Return ApplicabilityComparisonResult.LeftIsMoreApplicable End If If rightHasMoreApplicableParameterType Then Return ApplicabilityComparisonResult.RightIsMoreApplicable End If Return If(equallyApplicable, ApplicabilityComparisonResult.EquallyApplicable, ApplicabilityComparisonResult.Undefined) End Function Private Enum ApplicabilityComparisonResult Undefined EquallyApplicable LeftIsMoreApplicable RightIsMoreApplicable End Enum ''' <summary> ''' §11.8.1.1 Applicability ''' </summary> Private Shared Function CompareParameterTypeApplicability( left As TypeSymbol, right As TypeSymbol, argument As BoundExpression, binder As Binder, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) As ApplicabilityComparisonResult Debug.Assert(argument Is Nothing OrElse argument.Kind <> BoundKind.OmittedArgument) ' §11.8.1.1 Applicability 'Given a pair of parameters Mj and Nj that matches an argument Aj, 'the type of Mj is considered more applicable than the type of Nj if one of the following conditions is true: Dim leftToRightConversion = Conversions.ClassifyConversion(left, right, useSiteInfo) '1. Mj and Nj have identical types, or ' !!! Does this rule make sense? Not implementing it for now. If Conversions.IsIdentityConversion(leftToRightConversion.Key) Then Return ApplicabilityComparisonResult.EquallyApplicable End If '2. There exists a widening conversion from the type of Mj to the type Nj, or If Conversions.IsWideningConversion(leftToRightConversion.Key) Then ' !!! For user defined conversions that widen in both directions there is a tie-breaking rule ' !!! not mentioned in the spec. The type that matches argument's type is more applicable. ' !!! Otherwise neither is more applicable. If Conversions.IsWideningConversion(Conversions.ClassifyConversion(right, left, useSiteInfo).Key) Then GoTo BreakTheTie End If ' !!! Spec makes it look like rule #3 is a separate rule applied after the second, but this isn't the case ' !!! because enumerated type widens to its underlying type, however, if argument is a zero literal, ' !!! underlying type should win. ' !!! Also, based on Dev10 implementation, Mj doesn't have to be a numeric type, it is enough if it is not ' !!! an enumerated type. '3. Aj is the literal 0, Mj is a numeric type and Nj is an enumerated type, or If argument IsNot Nothing AndAlso argument.IsIntegerZeroLiteral AndAlso left.TypeKind = TypeKind.Enum AndAlso right.TypeKind <> TypeKind.Enum Then Return ApplicabilityComparisonResult.RightIsMoreApplicable End If Return ApplicabilityComparisonResult.LeftIsMoreApplicable End If If Conversions.IsWideningConversion(Conversions.ClassifyConversion(right, left, useSiteInfo).Key) Then ' !!! Spec makes it look like rule #3 is a separate rule applied after the second, but this isn't the case ' !!! because enumerated type widens to its underlying type, however, if argument is a zero literal, ' !!! underlying type should win. ' !!! Also, based on Dev10 implementation, Mj doesn't have to be a numeric type, it is enough if it is not ' !!! an enumerated type. '3. Aj is the literal 0, Mj is a numeric type and Nj is an enumerated type, or If argument IsNot Nothing AndAlso argument.IsIntegerZeroLiteral AndAlso right.TypeKind = TypeKind.Enum AndAlso left.TypeKind <> TypeKind.Enum Then Return ApplicabilityComparisonResult.LeftIsMoreApplicable End If Return ApplicabilityComparisonResult.RightIsMoreApplicable End If ''3. Aj is the literal 0, Mj is a numeric type and Nj is an enumerated type, or 'If argument IsNot Nothing AndAlso argument.IsIntegerZeroLiteral Then ' If left.IsNumericType() Then ' If right.TypeKind = TypeKind.Enum Then ' leftIsMoreApplicable = True ' Return ' End If ' ElseIf right.IsNumericType() Then ' If left.TypeKind = TypeKind.Enum Then ' rightIsMoreApplicable = True ' Return ' End If ' End If 'End If '4. Mj is Byte and Nj is SByte, or '5. Mj is Short and Nj is UShort, or '6. Mj is Integer and Nj is UInteger, or '7. Mj is Long and Nj is ULong. '!!! Plus rules not mentioned in the spec If left.IsNumericType() AndAlso right.IsNumericType() Then Dim leftSpecialType = left.SpecialType Dim rightSpecialType = right.SpecialType If leftSpecialType = SpecialType.System_Byte AndAlso rightSpecialType = SpecialType.System_SByte Then Return ApplicabilityComparisonResult.LeftIsMoreApplicable End If If leftSpecialType = SpecialType.System_SByte AndAlso rightSpecialType = SpecialType.System_Byte Then Return ApplicabilityComparisonResult.RightIsMoreApplicable End If ' This comparison depends on the ordering of the SpecialType enum. There is a unit-test that verifies the ordering. If leftSpecialType < rightSpecialType Then Return ApplicabilityComparisonResult.LeftIsMoreApplicable Else Debug.Assert(rightSpecialType < leftSpecialType) Return ApplicabilityComparisonResult.RightIsMoreApplicable End If End If '8. Mj and Nj are delegate function types and the return type of Mj is more specific than the return type of Nj. ' If Aj is classified as a lambda method, and Mj or Nj is System.Linq.Expressions.Expression(Of T), then the ' type argument of the type (assuming it is a delegate type) is substituted for the type being compared. If argument IsNot Nothing Then Dim leftIsExpressionTree As Boolean, rightIsExpressionTree As Boolean Dim leftDelegateType As NamedTypeSymbol = left.DelegateOrExpressionDelegate(binder, leftIsExpressionTree) Dim rightDelegateType As NamedTypeSymbol = right.DelegateOrExpressionDelegate(binder, rightIsExpressionTree) ' Native compiler will only compare D1 and D2 for Expression(Of D1) and D2 if the argument is a lambda. It will compare ' Expression(Of D1) and Expression (Of D2) regardless of the argument. If leftDelegateType IsNot Nothing AndAlso rightDelegateType IsNot Nothing AndAlso ((leftIsExpressionTree = rightIsExpressionTree) OrElse argument.IsAnyLambda()) Then Dim leftInvoke As MethodSymbol = leftDelegateType.DelegateInvokeMethod Dim rightInvoke As MethodSymbol = rightDelegateType.DelegateInvokeMethod If leftInvoke IsNot Nothing AndAlso Not leftInvoke.IsSub AndAlso rightInvoke IsNot Nothing AndAlso Not rightInvoke.IsSub Then Dim newArgument As BoundExpression = Nothing ' TODO: Should probably handle GroupTypeInferenceLambda too. If argument.Kind = BoundKind.QueryLambda Then newArgument = DirectCast(argument, BoundQueryLambda).Expression End If Return CompareParameterTypeApplicability(leftInvoke.ReturnType, rightInvoke.ReturnType, newArgument, binder, useSiteInfo) End If End If End If BreakTheTie: ' !!! There is a tie-breaking rule not mentioned in the spec. The type that matches argument's type is more applicable. ' !!! Otherwise neither is more applicable. If argument IsNot Nothing Then Dim argType As TypeSymbol = If(argument.Kind <> BoundKind.ArrayLiteral, argument.Type, DirectCast(argument, BoundArrayLiteral).InferredType) If argType IsNot Nothing Then If left.IsSameTypeIgnoringAll(argType) Then Return ApplicabilityComparisonResult.LeftIsMoreApplicable End If If right.IsSameTypeIgnoringAll(argType) Then Return ApplicabilityComparisonResult.RightIsMoreApplicable End If End If End If ' Neither is more applicable Return ApplicabilityComparisonResult.Undefined End Function ''' <summary> ''' This method groups equally applicable (§11.8.1.1 Applicability) candidates into buckets. ''' ''' Returns an ArrayBuilder of buckets. Each bucket is represented by an ArrayBuilder(Of Integer), ''' which contains indexes of equally applicable candidates from input parameter 'candidates'. ''' </summary> Private Shared Function GroupEquallyApplicableCandidates( candidates As ArrayBuilder(Of CandidateAnalysisResult), arguments As ImmutableArray(Of BoundExpression), binder As Binder ) As ArrayBuilder(Of ArrayBuilder(Of Integer)) Dim buckets = ArrayBuilder(Of ArrayBuilder(Of Integer)).GetInstance() Dim i As Integer Dim j As Integer ' §11.8.1.1 Applicability ' A member M is considered equally applicable as N if their signatures are the same or ' if each parameter type in M is the same as the corresponding parameter type in N. For i = 0 To candidates.Count - 1 Step 1 Dim left As CandidateAnalysisResult = candidates(i) If left.State <> CandidateAnalysisResultState.Applicable OrElse left.EquallyApplicableCandidatesBucket > 0 Then Continue For End If left.EquallyApplicableCandidatesBucket = buckets.Count + 1 candidates(i) = left Dim b = ArrayBuilder(Of Integer).GetInstance() b.Add(i) buckets.Add(b) For j = i + 1 To candidates.Count - 1 Step 1 Dim right As CandidateAnalysisResult = candidates(j) If right.State <> CandidateAnalysisResultState.Applicable OrElse right.EquallyApplicableCandidatesBucket > 0 OrElse right.Candidate Is left.Candidate Then Continue For End If If CandidatesAreEquallyApplicableToArguments(left, right, arguments, binder) Then right.EquallyApplicableCandidatesBucket = left.EquallyApplicableCandidatesBucket candidates(j) = right b.Add(j) End If Next Next Return buckets End Function Private Shared Function CandidatesAreEquallyApplicableToArguments( ByRef left As CandidateAnalysisResult, ByRef right As CandidateAnalysisResult, arguments As ImmutableArray(Of BoundExpression), binder As Binder ) As Boolean ' §11.8.1.1 Applicability ' A member M is considered equally applicable as N if their signatures are the same or ' if each parameter type in M is the same as the corresponding parameter type in N. ' Compare types of corresponding parameters Dim k As Integer Dim leftParamIndex As Integer = 0 Dim rightParamIndex As Integer = 0 For k = 0 To arguments.Length - 1 Step 1 Dim leftParamType As TypeSymbol Debug.Assert(left.ArgsToParamsOpt.IsDefault = right.ArgsToParamsOpt.IsDefault) If left.ArgsToParamsOpt.IsDefault Then leftParamType = GetParameterTypeFromVirtualSignature(left, leftParamIndex) AdvanceParameterInVirtualSignature(left, leftParamIndex) Else leftParamType = GetParameterTypeFromVirtualSignature(left, left.ArgsToParamsOpt(k)) End If Dim rightParamType As TypeSymbol If right.ArgsToParamsOpt.IsDefault Then rightParamType = GetParameterTypeFromVirtualSignature(right, rightParamIndex) AdvanceParameterInVirtualSignature(right, rightParamIndex) Else rightParamType = GetParameterTypeFromVirtualSignature(right, right.ArgsToParamsOpt(k)) End If ' Parameters matching omitted arguments do not participate. If arguments(k).Kind <> BoundKind.OmittedArgument AndAlso Not ParametersAreEquallyApplicableToArgument(leftParamType, rightParamType, arguments(k), binder) Then ' Signatures are different Exit For End If Next Return k >= arguments.Length End Function Private Shared Function ParametersAreEquallyApplicableToArgument( leftParamType As TypeSymbol, rightParamType As TypeSymbol, argument As BoundExpression, binder As Binder ) As Boolean Debug.Assert(argument Is Nothing OrElse argument.Kind <> BoundKind.OmittedArgument) If Not leftParamType.IsSameTypeIgnoringAll(rightParamType) Then If argument IsNot Nothing Then Dim leftIsExpressionTree As Boolean, rightIsExpressionTree As Boolean Dim leftDelegateType As NamedTypeSymbol = leftParamType.DelegateOrExpressionDelegate(binder, leftIsExpressionTree) Dim rightDelegateType As NamedTypeSymbol = rightParamType.DelegateOrExpressionDelegate(binder, rightIsExpressionTree) ' Native compiler will only compare D1 and D2 for Expression(Of D1) and D2 if the argument is a lambda. It will compare ' Expression(Of D1) and Expression (Of D2) regardless of the argument. If leftDelegateType IsNot Nothing AndAlso rightDelegateType IsNot Nothing AndAlso ((leftIsExpressionTree = rightIsExpressionTree) OrElse argument.IsAnyLambda()) Then Dim leftInvoke As MethodSymbol = leftDelegateType.DelegateInvokeMethod Dim rightInvoke As MethodSymbol = rightDelegateType.DelegateInvokeMethod If leftInvoke IsNot Nothing AndAlso Not leftInvoke.IsSub AndAlso rightInvoke IsNot Nothing AndAlso Not rightInvoke.IsSub Then Dim newArgument As BoundExpression = Nothing ' TODO: Should probably handle GroupTypeInferenceLambda too. If argument.Kind = BoundKind.QueryLambda Then newArgument = DirectCast(argument, BoundQueryLambda).Expression End If Return ParametersAreEquallyApplicableToArgument(leftInvoke.ReturnType, rightInvoke.ReturnType, newArgument, binder) End If End If End If ' Signatures are different Return False End If Return True End Function ''' <summary> ''' §11.8.1 Overloaded Method Resolution ''' 3. Next, eliminate all members from the set that require narrowing conversions ''' to be applicable to the argument list, except for the case where the argument ''' expression type is Object. ''' 4. Next, eliminate all remaining members from the set that require narrowing coercions ''' to be applicable to the argument list. If the set is empty, the type containing the ''' method group is not an interface, and strict semantics are not being used, the ''' invocation target expression is reclassified as a late-bound method access. ''' Otherwise, the normal rules apply. ''' ''' Returns amount of applicable candidates left. ''' </summary> ''' <returns></returns> ''' <remarks></remarks> Private Shared Function AnalyzeNarrowingCandidates( candidates As ArrayBuilder(Of CandidateAnalysisResult), arguments As ImmutableArray(Of BoundExpression), delegateReturnType As TypeSymbol, lateBindingIsAllowed As Boolean, binder As Binder, ByRef resolutionIsLateBound As Boolean, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) As Integer Dim applicableCandidates As Integer = 0 Dim appliedTieBreakingRules As Boolean = False ' Look through the candidate set for lifted operators that require narrowing conversions whose ' source operators also require narrowing conversions. In that case, we only want to keep one method in ' the set. If the source operator requires nullables to be unwrapped, then we discard it and keep the lifted operator. ' If it does not, then we discard the lifted operator and keep the source operator. This will prevent the presence of ' lifted operators from causing overload resolution conflicts where there otherwise wouldn't be one. However, ' if the source operator only requires narrowing conversions from numeric literals, then we keep both in the set, ' because the conversion in that case is not really narrowing. If candidates(0).Candidate.IsOperator Then ' As an optimization, we can rely on the fact that lifted operator, if added, immediately ' follows source operator. Dim i As Integer For i = 0 To candidates.Count - 2 Step 1 Dim current As CandidateAnalysisResult = candidates(i) Debug.Assert(current.Candidate.IsOperator) If current.State = CandidateAnalysisResultState.Applicable AndAlso Not current.Candidate.IsLifted AndAlso current.RequiresNarrowingNotFromNumericConstant Then Dim contender As CandidateAnalysisResult = candidates(i + 1) Debug.Assert(contender.Candidate.IsOperator) If contender.State = CandidateAnalysisResultState.Applicable AndAlso contender.Candidate.IsLifted AndAlso current.Candidate.UnderlyingSymbol Is contender.Candidate.UnderlyingSymbol Then Exit For End If End If Next If i < candidates.Count - 1 Then ' [i] is the index of the first "interesting" pair of source/lifted operators. If Not appliedTieBreakingRules Then ' Apply shadowing rules, Dev10 compiler does that for narrowing candidates too. applicableCandidates = ApplyTieBreakingRulesToEquallyApplicableCandidates(candidates, arguments, delegateReturnType, binder, useSiteInfo) appliedTieBreakingRules = True Debug.Assert(applicableCandidates > 1) ' source and lifted operators are not equally applicable. End If ' Let's do the elimination pass now. For i = i To candidates.Count - 2 Step 1 Dim current As CandidateAnalysisResult = candidates(i) Debug.Assert(current.Candidate.IsOperator) If current.State = CandidateAnalysisResultState.Applicable AndAlso Not current.Candidate.IsLifted AndAlso current.RequiresNarrowingNotFromNumericConstant Then Dim contender As CandidateAnalysisResult = candidates(i + 1) Debug.Assert(contender.Candidate.IsOperator) If contender.State = CandidateAnalysisResultState.Applicable AndAlso contender.Candidate.IsLifted AndAlso current.Candidate.UnderlyingSymbol Is contender.Candidate.UnderlyingSymbol Then For j As Integer = 0 To arguments.Length - 1 Dim conv As KeyValuePair(Of ConversionKind, MethodSymbol) = current.ConversionsOpt(j) If Conversions.IsNarrowingConversion(conv.Key) Then Dim lost As Boolean = False If (conv.Key And ConversionKind.UserDefined) = 0 Then If IsUnwrappingNullable(conv.Key, arguments(j).Type, current.Candidate.Parameters(j).Type) Then lost = True End If Else ' Lifted user-defined conversions don't unwrap nullables, they are marked with Nullable bit. If (conv.Key And ConversionKind.Nullable) = 0 Then If IsUnwrappingNullable(arguments(j).Type, conv.Value.Parameters(0).Type, useSiteInfo) Then lost = True ElseIf IsUnwrappingNullable(conv.Value.ReturnType, current.Candidate.Parameters(j).Type, useSiteInfo) Then lost = True End If End If End If If lost Then ' unwrapping nullable, current lost current.State = CandidateAnalysisResultState.Shadowed candidates(i) = current i = i + 1 GoTo Next_i End If End If Next ' contender lost contender.State = CandidateAnalysisResultState.Shadowed candidates(i + 1) = contender i = i + 1 GoTo Next_i End If End If Next_i: Next End If End If If lateBindingIsAllowed Then ' Are there all narrowing from object candidates? Dim haveAllNarrowingFromObject As Boolean = HaveNarrowingOnlyFromObjectCandidates(candidates) If haveAllNarrowingFromObject AndAlso Not appliedTieBreakingRules Then ' Apply shadowing rules, Dev10 compiler does that for narrowing candidates too. applicableCandidates = ApplyTieBreakingRulesToEquallyApplicableCandidates(candidates, arguments, delegateReturnType, binder, useSiteInfo) appliedTieBreakingRules = True If applicableCandidates < 2 Then Return applicableCandidates End If haveAllNarrowingFromObject = HaveNarrowingOnlyFromObjectCandidates(candidates) End If If haveAllNarrowingFromObject Then ' Get rid of candidates that require narrowing from something other than Object applicableCandidates = 0 For i As Integer = 0 To candidates.Count - 1 Step 1 Dim current As CandidateAnalysisResult = candidates(i) If current.State = CandidateAnalysisResultState.Applicable Then If (current.RequiresNarrowingNotFromObject OrElse current.Candidate.IsExtensionMethod) Then current.State = CandidateAnalysisResultState.ExtensionMethodVsLateBinding candidates(i) = current Else applicableCandidates += 1 End If End If Next Debug.Assert(applicableCandidates > 0) If applicableCandidates > 1 Then resolutionIsLateBound = True End If Return applicableCandidates End If End If ' Although all candidates narrow, there may be a best choice when factoring in narrowing of numeric constants. ' Note that EliminateLessApplicableToTheArguments applies shadowing rules, Dev10 compiler does that for narrowing candidates too. applicableCandidates = EliminateLessApplicableToTheArguments(candidates, arguments, delegateReturnType, appliedTieBreakingRules, binder, mostApplicableMustNarrowOnlyFromNumericConstants:=True, useSiteInfo:=useSiteInfo) ' If we ended up with 2 applicable candidates, make sure it is not the same method in ' ParamArray expanded and non-expanded form. The non-expanded form should win in this case. If applicableCandidates = 2 Then For i As Integer = 0 To candidates.Count - 1 Step 1 Dim first As CandidateAnalysisResult = candidates(i) If first.State = CandidateAnalysisResultState.Applicable Then For j As Integer = i + 1 To candidates.Count - 1 Step 1 Dim second As CandidateAnalysisResult = candidates(j) If second.State = CandidateAnalysisResultState.Applicable Then If first.Candidate.UnderlyingSymbol.Equals(second.Candidate.UnderlyingSymbol) Then Dim firstWins As Boolean = False Dim secondWins As Boolean = False If ShadowBasedOnParamArrayUsage(first, second, firstWins, secondWins) Then If firstWins Then second.State = CandidateAnalysisResultState.Shadowed candidates(j) = second applicableCandidates = 1 ElseIf secondWins Then first.State = CandidateAnalysisResultState.Shadowed candidates(i) = first applicableCandidates = 1 End If Debug.Assert(applicableCandidates = 1) End If End If GoTo Done End If Next Debug.Assert(False, "Should not reach this line.") End If Next End If Done: Return applicableCandidates End Function Private Shared Function IsUnwrappingNullable( conv As ConversionKind, sourceType As TypeSymbol, targetType As TypeSymbol ) As Boolean Debug.Assert((conv And ConversionKind.UserDefined) = 0) Return (conv And ConversionKind.Nullable) <> 0 AndAlso sourceType IsNot Nothing AndAlso sourceType.IsNullableType() AndAlso Not targetType.IsNullableType() End Function Private Shared Function IsUnwrappingNullable( sourceType As TypeSymbol, targetType As TypeSymbol, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) As Boolean Return sourceType IsNot Nothing AndAlso IsUnwrappingNullable(Conversions.ClassifyPredefinedConversion(sourceType, targetType, useSiteInfo), sourceType, targetType) End Function Private Shared Function HaveNarrowingOnlyFromObjectCandidates( candidates As ArrayBuilder(Of CandidateAnalysisResult) ) As Boolean Dim haveAllNarrowingFromObject As Boolean = False For i As Integer = 0 To candidates.Count - 1 Step 1 Dim current As CandidateAnalysisResult = candidates(i) If current.State = CandidateAnalysisResultState.Applicable AndAlso Not current.RequiresNarrowingNotFromObject AndAlso Not current.Candidate.IsExtensionMethod Then haveAllNarrowingFromObject = True Exit For End If Next Return haveAllNarrowingFromObject End Function ''' <summary> ''' §11.8.1 Overloaded Method Resolution ''' 2. Next, eliminate all members from the set that are inaccessible or not applicable to the argument list. ''' ''' Note, similar to Dev10 compiler this process will eliminate candidates requiring narrowing conversions ''' if strict semantics is used, exception are candidates that require narrowing only from numeric constants. ''' ''' Returns amount of applicable candidates left. ''' </summary> ''' <returns></returns> ''' <remarks></remarks> Private Shared Function EliminateNotApplicableToArguments( methodOrPropertyGroup As BoundMethodOrPropertyGroup, candidates As ArrayBuilder(Of CandidateAnalysisResult), arguments As ImmutableArray(Of BoundExpression), argumentNames As ImmutableArray(Of String), binder As Binder, <Out()> ByRef applicableNarrowingCandidates As Integer, <[In](), Out()> ByRef asyncLambdaSubToFunctionMismatch As HashSet(Of BoundExpression), callerInfoOpt As SyntaxNode, forceExpandedForm As Boolean, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) As Integer Dim applicableCandidates As Integer = 0 Dim illegalInAttribute As Integer = 0 applicableNarrowingCandidates = 0 ' Filter out inapplicable candidates For i As Integer = 0 To candidates.Count - 1 Step 1 Dim current As CandidateAnalysisResult = candidates(i) If current.State <> CandidateAnalysisResultState.Applicable Then Continue For End If If Not current.ArgumentMatchingDone Then MatchArguments(methodOrPropertyGroup, current, arguments, argumentNames, binder, asyncLambdaSubToFunctionMismatch, callerInfoOpt, forceExpandedForm, useSiteInfo) current.SetArgumentMatchingDone() candidates(i) = current End If If current.State = CandidateAnalysisResultState.Applicable Then applicableCandidates += 1 If current.RequiresNarrowingConversion Then applicableNarrowingCandidates += 1 End If If current.IsIllegalInAttribute Then illegalInAttribute += 1 End If End If Next ' Filter out candidates with IsIllegalInAttribute if there are other applicable candidates If illegalInAttribute > 0 AndAlso applicableCandidates > illegalInAttribute Then For i As Integer = 0 To candidates.Count - 1 Step 1 Dim current As CandidateAnalysisResult = candidates(i) If current.State = CandidateAnalysisResultState.Applicable AndAlso current.IsIllegalInAttribute Then applicableCandidates -= 1 If current.RequiresNarrowingConversion Then applicableNarrowingCandidates -= 1 End If current.State = CandidateAnalysisResultState.ArgumentMismatch candidates(i) = current End If Next Debug.Assert(applicableCandidates > 0) End If Return applicableCandidates End Function ''' <summary> ''' Figure out corresponding arguments for parameters §11.8.2 Applicable Methods. ''' ''' Note, this function mutates the candidate structure. ''' ''' If non-Nothing ArrayBuilders are returned through parameterToArgumentMap and paramArrayItems ''' parameters, the caller is responsible fo returning them into the pool. ''' ''' Assumptions: ''' 1) This function is never called for a candidate that should be rejected due to parameter count. ''' 2) Omitted arguments [ Call Goo(a, , b) ] are represented by OmittedArgumentExpression node in the arguments array. ''' 3) Omitted argument never has name. ''' 4) argumentNames contains Nothing for all positional arguments. ''' ''' !!! Should keep this function in sync with Binder.PassArguments, which uses data this function populates. !!! ''' !!! Should keep this function in sync with Binder.ReportOverloadResolutionFailureForASingleCandidate. !!! ''' !!! Everything we flag as an error here, Binder.ReportOverloadResolutionFailureForASingleCandidate should detect as well. !!! ''' </summary> Private Shared Sub BuildParameterToArgumentMap( ByRef candidate As CandidateAnalysisResult, arguments As ImmutableArray(Of BoundExpression), argumentNames As ImmutableArray(Of String), ByRef parameterToArgumentMap As ArrayBuilder(Of Integer), ByRef paramArrayItems As ArrayBuilder(Of Integer) ) Debug.Assert(Not arguments.IsDefault) Debug.Assert(argumentNames.IsDefault OrElse (argumentNames.Length > 0 AndAlso argumentNames.Length = arguments.Length)) Debug.Assert(Not candidate.ArgumentMatchingDone) Debug.Assert(candidate.State = CandidateAnalysisResultState.Applicable) parameterToArgumentMap = ArrayBuilder(Of Integer).GetInstance(candidate.Candidate.ParameterCount, -1) Dim argsToParams As ArrayBuilder(Of Integer) = Nothing If Not argumentNames.IsDefault Then argsToParams = ArrayBuilder(Of Integer).GetInstance(arguments.Length, -1) End If paramArrayItems = Nothing If candidate.IsExpandedParamArrayForm Then paramArrayItems = ArrayBuilder(Of Integer).GetInstance() End If '§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 For i As Integer = 0 To arguments.Length - 1 Step 1 If Not argumentNames.IsDefault AndAlso argumentNames(i) IsNot Nothing Then ' A named argument If Not candidate.Candidate.TryGetNamedParamIndex(argumentNames(i), paramIndex) Then ' ERRID_NamedParamNotFound1 ' ERRID_NamedParamNotFound2 candidate.State = CandidateAnalysisResultState.ArgumentMismatch GoTo Bailout End If If paramIndex <> i Then ' all remaining arguments must be named Exit For End If If paramIndex = candidate.Candidate.ParameterCount - 1 AndAlso candidate.Candidate.Parameters(paramIndex).IsParamArray Then ' ERRID_NamedParamArrayArgument candidate.State = CandidateAnalysisResultState.ArgumentMismatch GoTo Bailout End If Debug.Assert(parameterToArgumentMap(paramIndex) = -1) End If positionalArguments += 1 If argsToParams IsNot Nothing Then argsToParams(i) = paramIndex End If If arguments(i).Kind = BoundKind.OmittedArgument Then If paramIndex = candidate.Candidate.ParameterCount - 1 AndAlso candidate.Candidate.Parameters(paramIndex).IsParamArray Then ' Omitted ParamArray argument at the call site ' ERRID_OmittedParamArrayArgument candidate.State = CandidateAnalysisResultState.ArgumentMismatch GoTo Bailout Else parameterToArgumentMap(paramIndex) = i paramIndex += 1 End If ElseIf (candidate.IsExpandedParamArrayForm AndAlso paramIndex = candidate.Candidate.ParameterCount - 1) Then paramArrayItems.Add(i) Else parameterToArgumentMap(paramIndex) = i paramIndex += 1 End If Next '§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 named arguments, parser should have detected an error. candidate.State = CandidateAnalysisResultState.ArgumentMismatch GoTo Bailout 'Continue For End If If Not candidate.Candidate.TryGetNamedParamIndex(argumentNames(i), paramIndex) Then ' ERRID_NamedParamNotFound1 ' ERRID_NamedParamNotFound2 candidate.State = CandidateAnalysisResultState.ArgumentMismatch GoTo Bailout 'Continue For End If If argsToParams IsNot Nothing Then argsToParams(i) = paramIndex End If If paramIndex = candidate.Candidate.ParameterCount - 1 AndAlso candidate.Candidate.Parameters(paramIndex).IsParamArray Then ' ERRID_NamedParamArrayArgument candidate.State = CandidateAnalysisResultState.ArgumentMismatch GoTo Bailout 'Continue For End If If parameterToArgumentMap(paramIndex) <> -1 Then ' ERRID_NamedArgUsedTwice1 ' ERRID_NamedArgUsedTwice2 ' ERRID_NamedArgUsedTwice3 candidate.State = CandidateAnalysisResultState.ArgumentMismatch GoTo Bailout '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 candidate.State = CandidateAnalysisResultState.ArgumentMismatch GoTo Bailout 'Continue For End If parameterToArgumentMap(paramIndex) = i Next If argsToParams IsNot Nothing Then candidate.ArgsToParamsOpt = argsToParams.ToImmutableAndFree() argsToParams = Nothing End If Bailout: If argsToParams IsNot Nothing Then argsToParams.Free() argsToParams = Nothing End If End Sub ''' <summary> ''' Match candidate's parameters to arguments §11.8.2 Applicable Methods. ''' ''' Note, similar to Dev10 compiler this process will eliminate candidate requiring narrowing conversions ''' if strict semantics is used, exception are candidates that require narrowing only from numeric constants. ''' ''' Assumptions: ''' 1) This function is never called for a candidate that should be rejected due to parameter count. ''' 2) Omitted arguments [ Call Goo(a, , b) ] are represented by OmittedArgumentExpression node in the arguments array. ''' 3) Omitted argument never has name. ''' 4) argumentNames contains Nothing for all positional arguments. ''' ''' !!! Should keep this function in sync with Binder.PassArguments, which uses data this function populates. !!! ''' !!! Should keep this function in sync with Binder.ReportOverloadResolutionFailureForASingleCandidate. !!! ''' !!! Should keep this function in sync with InferenceGraph.PopulateGraph. !!! ''' !!! Everything we flag as an error here, Binder.ReportOverloadResolutionFailureForASingleCandidate should detect as well. !!! ''' </summary> Private Shared Sub MatchArguments( methodOrPropertyGroup As BoundMethodOrPropertyGroup, ByRef candidate As CandidateAnalysisResult, arguments As ImmutableArray(Of BoundExpression), argumentNames As ImmutableArray(Of String), binder As Binder, <[In](), Out()> ByRef asyncLambdaSubToFunctionMismatch As HashSet(Of BoundExpression), callerInfoOpt As SyntaxNode, forceExpandedForm As Boolean, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) Debug.Assert(Not arguments.IsDefault) Debug.Assert(argumentNames.IsDefault OrElse (argumentNames.Length > 0 AndAlso argumentNames.Length = arguments.Length)) Debug.Assert(Not candidate.ArgumentMatchingDone) Debug.Assert(candidate.State = CandidateAnalysisResultState.Applicable) Debug.Assert(Not candidate.Candidate.UnderlyingSymbol.IsReducedExtensionMethod() OrElse methodOrPropertyGroup.ReceiverOpt IsNot Nothing OrElse TypeOf methodOrPropertyGroup.SyntaxTree Is DummySyntaxTree) Dim parameterToArgumentMap As ArrayBuilder(Of Integer) = Nothing Dim paramArrayItems As ArrayBuilder(Of Integer) = Nothing Dim conversionKinds As KeyValuePair(Of ConversionKind, MethodSymbol)() = Nothing Dim conversionBackKinds As KeyValuePair(Of ConversionKind, MethodSymbol)() = Nothing Dim optionalArguments As OptionalArgument() = Nothing Dim defaultValueDiagnostics As BindingDiagnosticBag = Nothing BuildParameterToArgumentMap(candidate, arguments, argumentNames, parameterToArgumentMap, paramArrayItems) If candidate.State <> CandidateAnalysisResultState.Applicable Then Debug.Assert(Not candidate.IgnoreExtensionMethods) GoTo Bailout End If ' At this point we will set IgnoreExtensionMethods to true and will ' clear it when appropriate because not every failure should allow ' us to consider extension methods. If Not candidate.Candidate.IsExtensionMethod Then candidate.IgnoreExtensionMethods = True End If '§11.8.2 Applicable Methods 'The type arguments, if any, must satisfy the constraints, if any, on the matching type parameters. Dim candidateSymbol = candidate.Candidate.UnderlyingSymbol If candidateSymbol.Kind = SymbolKind.Method Then Dim method = DirectCast(candidateSymbol, MethodSymbol) If method.IsGenericMethod Then Dim diagnosticsBuilder = ArrayBuilder(Of TypeParameterDiagnosticInfo).GetInstance() Dim useSiteDiagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo) = Nothing Dim satisfiedConstraints = method.CheckConstraints(binder.Compilation.LanguageVersion, diagnosticsBuilder, useSiteDiagnosticsBuilder, template:=useSiteInfo) diagnosticsBuilder.Free() If useSiteDiagnosticsBuilder IsNot Nothing AndAlso useSiteDiagnosticsBuilder.Count > 0 Then For Each diag In useSiteDiagnosticsBuilder useSiteInfo.Add(diag.UseSiteInfo) Next End If If Not satisfiedConstraints Then ' Do not clear IgnoreExtensionMethods flag if constraints are violated. candidate.State = CandidateAnalysisResultState.GenericConstraintsViolated GoTo Bailout End If End If End If ' Traverse the parameters, converting corresponding arguments ' as appropriate. Dim argIndex As Integer Dim candidateIsAProperty As Boolean = (candidate.Candidate.UnderlyingSymbol.Kind = SymbolKind.Property) For paramIndex = 0 To candidate.Candidate.ParameterCount - 1 Step 1 If candidate.State <> CandidateAnalysisResultState.Applicable AndAlso Not candidate.IgnoreExtensionMethods Then ' There is no reason to continue. We will not learn anything new. GoTo Bailout End If Dim param As ParameterSymbol = candidate.Candidate.Parameters(paramIndex) Dim isByRef As Boolean = param.IsByRef Dim targetType As TypeSymbol = param.Type If param.IsParamArray AndAlso paramIndex = candidate.Candidate.ParameterCount - 1 Then If targetType.Kind <> SymbolKind.ArrayType Then ' ERRID_ParamArrayWrongType candidate.State = CandidateAnalysisResultState.ArgumentMismatch candidate.IgnoreExtensionMethods = False GoTo Bailout 'Continue For End If If Not candidate.IsExpandedParamArrayForm Then argIndex = parameterToArgumentMap(paramIndex) Dim paramArrayArgument = If(argIndex = -1, Nothing, arguments(argIndex)) Debug.Assert(paramArrayArgument Is Nothing OrElse paramArrayArgument.Kind <> BoundKind.OmittedArgument) '§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. '!!! However, there is an exception to that rule - narrowing conversion from semantical Nothing literal is Ok. !!! Dim arrayConversion As KeyValuePair(Of ConversionKind, MethodSymbol) = Nothing If Not (paramArrayArgument IsNot Nothing AndAlso Not paramArrayArgument.HasErrors AndAlso CanPassToParamArray(paramArrayArgument, targetType, arrayConversion, binder, useSiteInfo)) Then ' It doesn't look like native compiler reports any errors in this case. ' Probably due to assumption that either errors were already reported for bad argument expression or ' we will report errors for expanded version of the same candidate. candidate.State = CandidateAnalysisResultState.ArgumentMismatch candidate.IgnoreExtensionMethods = False GoTo Bailout 'Continue For ElseIf Conversions.IsNarrowingConversion(arrayConversion.Key) Then ' We can get here only for Object with constant value == Nothing. Debug.Assert(paramArrayArgument.IsNothingLiteral()) ' Unlike for other arguments, Dev10 doesn't make a note of this narrowing. ' However, should this narrowing cause a conversion error, the error must be noted. If binder.OptionStrict = OptionStrict.On Then candidate.State = CandidateAnalysisResultState.ArgumentMismatch ' Note, this doesn't clear IgnoreExtensionMethods flag. Continue For End If Else Debug.Assert(Conversions.IsWideningConversion(arrayConversion.Key)) End If ' Since CanPassToParamArray succeeded, there is no need to check conversions for this argument again If Not Conversions.IsIdentityConversion(arrayConversion.Key) Then If conversionKinds Is Nothing Then conversionKinds = New KeyValuePair(Of ConversionKind, MethodSymbol)(arguments.Length - 1) {} For i As Integer = 0 To conversionKinds.Length - 1 conversionKinds(i) = Conversions.Identity Next End If conversionKinds(argIndex) = arrayConversion End If Else Debug.Assert(candidate.IsExpandedParamArrayForm) '§11.8.2 Applicable Methods ' If the argument expression is the literal Nothing, then the method is only applicable in its unexpanded form. ' Note, that explicitly converted NOTHING is treated the same way by Dev10. ' But, for the purpose of interpolated string lowering the method is applicable even if the argument expression ' is the literal Nothing. This is because for interpolated string lowering we want to always call methods ' in their expanded form. E.g. $"{Nothing}" should be lowered to String.Format("{0}", New Object() {Nothing}) not ' String.Format("{0}", CType(Nothing, Object())). If paramArrayItems.Count = 1 AndAlso arguments(paramArrayItems(0)).IsNothingLiteral() AndAlso Not forceExpandedForm Then candidate.State = CandidateAnalysisResultState.ArgumentMismatch candidate.IgnoreExtensionMethods = False GoTo Bailout 'Continue For End If ' Otherwise, for a ParamArray parameter, all the matching arguments are passed ' ByVal as instances of the element type of the ParamArray. ' Perform the conversions to the element type of the ParamArray here. Dim arrayType = DirectCast(targetType, ArrayTypeSymbol) If Not arrayType.IsSZArray Then ' ERRID_ParamArrayWrongType candidate.State = CandidateAnalysisResultState.ArgumentMismatch candidate.IgnoreExtensionMethods = False GoTo Bailout 'Continue For End If targetType = arrayType.ElementType If targetType.Kind = SymbolKind.ErrorType Then candidate.State = CandidateAnalysisResultState.ArgumentMismatch ' Note, IgnoreExtensionMethods is not cleared. Continue For End If For j As Integer = 0 To paramArrayItems.Count - 1 Step 1 Dim conv As KeyValuePair(Of ConversionKind, MethodSymbol) = Nothing If arguments(paramArrayItems(j)).HasErrors Then ' UNDONE: should HasErrors really always cause argument mismatch [petergo, 3/9/2011] candidate.State = CandidateAnalysisResultState.ArgumentMismatch candidate.IgnoreExtensionMethods = False GoTo Bailout 'Continue For End If If Not MatchArgumentToByValParameter(methodOrPropertyGroup, candidate, arguments(paramArrayItems(j)), targetType, binder, conv, asyncLambdaSubToFunctionMismatch, useSiteInfo) Then ' Note, IgnoreExtensionMethods is not cleared here, MatchArgumentToByValParameter makes required changes. Continue For End If ' typically all conversions in otherwise acceptable candidate are identity conversions If Not Conversions.IsIdentityConversion(conv.Key) Then If conversionKinds Is Nothing Then conversionKinds = New KeyValuePair(Of ConversionKind, MethodSymbol)(arguments.Length - 1) {} For i As Integer = 0 To conversionKinds.Length - 1 conversionKinds(i) = Conversions.Identity Next End If conversionKinds(paramArrayItems(j)) = conv End If Next End If Continue For End If argIndex = parameterToArgumentMap(paramIndex) Dim argument = If(argIndex = -1, Nothing, arguments(argIndex)) Dim defaultArgument As BoundExpression = Nothing If argument Is Nothing OrElse argument.Kind = BoundKind.OmittedArgument Then ' Deal with Optional arguments. If defaultValueDiagnostics Is Nothing Then defaultValueDiagnostics = BindingDiagnosticBag.GetInstance() Else defaultValueDiagnostics.Clear() End If Dim receiverOpt As BoundExpression = Nothing If candidateSymbol.IsReducedExtensionMethod() Then receiverOpt = methodOrPropertyGroup.ReceiverOpt End If defaultArgument = binder.GetArgumentForParameterDefaultValue(param, If(argument, methodOrPropertyGroup).Syntax, defaultValueDiagnostics, callerInfoOpt, parameterToArgumentMap, arguments, receiverOpt) If defaultArgument IsNot Nothing AndAlso Not defaultValueDiagnostics.HasAnyErrors Then Debug.Assert(Not defaultValueDiagnostics.DiagnosticBag.AsEnumerable().Any()) ' Mark these as compiler generated so they are ignored by later phases. For example, ' these bound nodes will mess up the incremental binder cache, because they use the ' the same syntax node as the method identifier from the invocation / AddressOf if they ' are not marked. defaultArgument.SetWasCompilerGenerated() argument = defaultArgument Else candidate.State = CandidateAnalysisResultState.ArgumentMismatch 'Note, IgnoreExtensionMethods flag should not be cleared due to a badness of default value. candidate.IgnoreExtensionMethods = False GoTo Bailout End If End If If targetType.Kind = SymbolKind.ErrorType Then candidate.State = CandidateAnalysisResultState.ArgumentMismatch ' Note, IgnoreExtensionMethods is not cleared. Continue For End If If argument.HasErrors Then ' UNDONE: should HasErrors really always cause argument mismatch [petergo, 3/9/2011] candidate.State = CandidateAnalysisResultState.ArgumentMismatch candidate.IgnoreExtensionMethods = False GoTo Bailout End If Dim conversion As KeyValuePair(Of ConversionKind, MethodSymbol) = Nothing Dim conversionBack As KeyValuePair(Of ConversionKind, MethodSymbol) = Nothing 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. ' 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 defaultArgument Is Nothing AndAlso (param.IsExplicitByRef OrElse (argument.Type IsNot Nothing AndAlso argument.Type.IsStringType())) Then MatchArgumentToByRefParameter(methodOrPropertyGroup, candidate, argument, targetType, binder, conversion, conversionBack, asyncLambdaSubToFunctionMismatch, useSiteInfo) Else conversionBack = Conversions.Identity MatchArgumentToByValParameter(methodOrPropertyGroup, candidate, argument, targetType, binder, conversion, asyncLambdaSubToFunctionMismatch, useSiteInfo, defaultArgument IsNot Nothing) End If ' typically all conversions in otherwise acceptable candidate are identity conversions If Not Conversions.IsIdentityConversion(conversion.Key) Then If conversionKinds Is Nothing Then conversionKinds = New KeyValuePair(Of ConversionKind, MethodSymbol)(arguments.Length - 1) {} For i As Integer = 0 To conversionKinds.Length - 1 conversionKinds(i) = Conversions.Identity Next End If ' If this is not a default argument then store the conversion in the conversionKinds. ' For default arguments the conversion is stored below. If defaultArgument Is Nothing Then conversionKinds(argIndex) = conversion End If End If ' If this is a default argument then add it to the candidate result default arguments. ' Note these arguments are stored by parameter index. Default arguments are missing so they ' may not have an argument index. If defaultArgument IsNot Nothing Then If optionalArguments Is Nothing Then optionalArguments = New OptionalArgument(candidate.Candidate.ParameterCount - 1) {} End If optionalArguments(paramIndex) = New OptionalArgument(defaultArgument, conversion, defaultValueDiagnostics.DependenciesBag.ToImmutableArray()) End If If Not Conversions.IsIdentityConversion(conversionBack.Key) Then If conversionBackKinds Is Nothing Then ' There should never be a copy back conversion with a default argument. Debug.Assert(defaultArgument Is Nothing) conversionBackKinds = New KeyValuePair(Of ConversionKind, MethodSymbol)(arguments.Length - 1) {} For i As Integer = 0 To conversionBackKinds.Length - 1 conversionBackKinds(i) = Conversions.Identity Next End If conversionBackKinds(argIndex) = conversionBack End If Next Bailout: If defaultValueDiagnostics IsNot Nothing Then defaultValueDiagnostics.Free() End If If paramArrayItems IsNot Nothing Then paramArrayItems.Free() End If If conversionKinds IsNot Nothing Then candidate.ConversionsOpt = conversionKinds.AsImmutableOrNull() End If If conversionBackKinds IsNot Nothing Then candidate.ConversionsBackOpt = conversionBackKinds.AsImmutableOrNull() End If If optionalArguments IsNot Nothing Then candidate.OptionalArguments = optionalArguments.AsImmutableOrNull() End If If parameterToArgumentMap IsNot Nothing Then parameterToArgumentMap.Free() End If End Sub ''' <summary> ''' Should be in sync with Binder.ReportByRefConversionErrors. ''' </summary> Private Shared Sub MatchArgumentToByRefParameter( methodOrPropertyGroup As BoundMethodOrPropertyGroup, ByRef candidate As CandidateAnalysisResult, argument As BoundExpression, targetType As TypeSymbol, binder As Binder, <Out()> ByRef outConversionKind As KeyValuePair(Of ConversionKind, MethodSymbol), <Out()> ByRef outConversionBackKind As KeyValuePair(Of ConversionKind, MethodSymbol), <[In](), Out()> ByRef asyncLambdaSubToFunctionMismatch As HashSet(Of BoundExpression), <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) If argument.IsSupportingAssignment() Then If argument.IsLValue() AndAlso targetType.IsSameTypeIgnoringAll(argument.Type) Then outConversionKind = Conversions.Identity outConversionBackKind = Conversions.Identity Else outConversionBackKind = Conversions.Identity If MatchArgumentToByValParameter(methodOrPropertyGroup, candidate, argument, targetType, binder, outConversionKind, asyncLambdaSubToFunctionMismatch, useSiteInfo) Then ' Check copy back conversion Dim copyBackType = argument.GetTypeOfAssignmentTarget() Dim conv As KeyValuePair(Of ConversionKind, MethodSymbol) = Conversions.ClassifyConversion(targetType, copyBackType, useSiteInfo) outConversionBackKind = conv If Conversions.NoConversion(conv.Key) Then candidate.State = CandidateAnalysisResultState.ArgumentMismatch ' Possible only with user-defined conversions, I think. candidate.IgnoreExtensionMethods = False Else If Conversions.IsNarrowingConversion(conv.Key) Then ' Similar to Dev10 compiler, we will eliminate candidate requiring narrowing conversions ' if strict semantics is used, exception are candidates that require narrowing only from ' numeric(Constants. candidate.SetRequiresNarrowingConversion() Debug.Assert((conv.Key And ConversionKind.InvolvesNarrowingFromNumericConstant) = 0) candidate.SetRequiresNarrowingNotFromNumericConstant() If binder.OptionStrict = OptionStrict.On Then candidate.State = CandidateAnalysisResultState.ArgumentMismatch Return End If If targetType.SpecialType <> SpecialType.System_Object Then candidate.SetRequiresNarrowingNotFromObject() End If End If candidate.RegisterDelegateRelaxationLevel(conv.Key) 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 binder.Report_ERRID_ReadOnlyInClosure(argument) Then candidate.State = CandidateAnalysisResultState.ArgumentMismatch ' Note, we do not change IgnoreExtensionMethods flag here. End If outConversionBackKind = Conversions.Identity MatchArgumentToByValParameter(methodOrPropertyGroup, candidate, argument, targetType, binder, outConversionKind, asyncLambdaSubToFunctionMismatch, useSiteInfo) End If End Sub ''' <summary> ''' Should be in sync with Binder.ReportByValConversionErrors. ''' </summary> Private Shared Function MatchArgumentToByValParameter( methodOrPropertyGroup As BoundMethodOrPropertyGroup, ByRef candidate As CandidateAnalysisResult, argument As BoundExpression, targetType As TypeSymbol, binder As Binder, <Out()> ByRef outConversionKind As KeyValuePair(Of ConversionKind, MethodSymbol), <[In](), Out()> ByRef asyncLambdaSubToFunctionMismatch As HashSet(Of BoundExpression), <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol), Optional isDefaultValueArgument As Boolean = False ) As Boolean outConversionKind = Nothing 'VBConversions.NoConversion ' 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() Then candidate.State = CandidateAnalysisResultState.ArgumentMismatch ' Note, IgnoreExtensionMethods is not cleared. Return False End If Dim conv As KeyValuePair(Of ConversionKind, MethodSymbol) = Conversions.ClassifyConversion(argument, targetType, binder, useSiteInfo) outConversionKind = conv If Conversions.NoConversion(conv.Key) Then candidate.State = CandidateAnalysisResultState.ArgumentMismatch candidate.IgnoreExtensionMethods = False If (conv.Key And (ConversionKind.DelegateRelaxationLevelMask Or ConversionKind.Lambda)) = (ConversionKind.DelegateRelaxationLevelInvalid Or ConversionKind.Lambda) Then ' Dig through parenthesized Dim underlying As BoundExpression = argument While underlying.Kind = BoundKind.Parenthesized AndAlso underlying.Type Is Nothing underlying = DirectCast(underlying, BoundParenthesized).Expression End While Dim unbound = If(underlying.Kind = BoundKind.UnboundLambda, DirectCast(underlying, UnboundLambda), Nothing) If unbound IsNot Nothing AndAlso Not unbound.IsFunctionLambda AndAlso (unbound.Flags And SourceMemberFlags.Async) <> 0 AndAlso targetType.IsDelegateType Then Dim delegateInvoke As MethodSymbol = DirectCast(targetType, NamedTypeSymbol).DelegateInvokeMethod Debug.Assert(delegateInvoke IsNot Nothing) If delegateInvoke IsNot Nothing Then Dim bound As BoundLambda = unbound.GetBoundLambda(New UnboundLambda.TargetSignature(delegateInvoke)) Debug.Assert(bound IsNot Nothing) If bound IsNot Nothing AndAlso (bound.MethodConversionKind And MethodConversionKind.AllErrorReasons) = MethodConversionKind.Error_SubToFunction AndAlso (Not bound.Diagnostics.Diagnostics.HasAnyErrors) Then If asyncLambdaSubToFunctionMismatch Is Nothing Then asyncLambdaSubToFunctionMismatch = New HashSet(Of BoundExpression)(ReferenceEqualityComparer.Instance) End If asyncLambdaSubToFunctionMismatch.Add(unbound) End If End If End If End If Return False End If ' Characteristics of conversion applied to a default value for an optional parameter shouldn't be used to disambiguate ' between two candidates. If Conversions.IsNarrowingConversion(conv.Key) Then ' Similar to Dev10 compiler, we will eliminate candidate requiring narrowing conversions ' if strict semantics is used, exception are candidates that require narrowing only from ' numeric constants. If Not isDefaultValueArgument Then candidate.SetRequiresNarrowingConversion() End If If (conv.Key And ConversionKind.InvolvesNarrowingFromNumericConstant) = 0 Then If Not isDefaultValueArgument Then candidate.SetRequiresNarrowingNotFromNumericConstant() End If If binder.OptionStrict = OptionStrict.On Then candidate.State = CandidateAnalysisResultState.ArgumentMismatch Return False End If End If Dim argumentType = argument.Type If argumentType Is Nothing OrElse argumentType.SpecialType <> SpecialType.System_Object Then If Not isDefaultValueArgument Then candidate.SetRequiresNarrowingNotFromObject() End If End If ElseIf (conv.Key And ConversionKind.InvolvesNarrowingFromNumericConstant) <> 0 Then ' Dev10 overload resolution treats conversions that involve narrowing from numeric constant type ' as narrowing. If Not isDefaultValueArgument Then candidate.SetRequiresNarrowingConversion() candidate.SetRequiresNarrowingNotFromObject() End If End If If Not isDefaultValueArgument Then candidate.RegisterDelegateRelaxationLevel(conv.Key) End If ' If we are in attribute context, keep track of candidates that will result in illegal arguments. ' They should be dismissed in favor of other applicable candidates. If binder.BindingLocation = BindingLocation.Attribute AndAlso Not candidate.IsIllegalInAttribute AndAlso Not methodOrPropertyGroup.WasCompilerGenerated AndAlso methodOrPropertyGroup.Kind = BoundKind.MethodGroup AndAlso IsWithinAppliedAttributeName(methodOrPropertyGroup.Syntax) AndAlso DirectCast(candidate.Candidate.UnderlyingSymbol, MethodSymbol).MethodKind = MethodKind.Constructor AndAlso binder.Compilation.GetWellKnownType(WellKnownType.System_Attribute).IsBaseTypeOf(candidate.Candidate.UnderlyingSymbol.ContainingType, useSiteInfo) Then Debug.Assert(Not argument.HasErrors) Dim passedExpression As BoundExpression = binder.PassArgumentByVal(argument, conv, targetType, BindingDiagnosticBag.Discarded) If Not passedExpression.IsConstant Then ' Trying to match native compiler behavior in Semantics::IsValidAttributeConstant Dim visitor As New Binder.AttributeExpressionVisitor(binder, passedExpression.HasErrors) visitor.VisitExpression(passedExpression, BindingDiagnosticBag.Discarded) If visitor.HasErrors Then candidate.SetIllegalInAttribute() End If End If End If Return True End Function Private Shared Function IsWithinAppliedAttributeName(syntax As SyntaxNode) As Boolean Dim parent As SyntaxNode = syntax.Parent While parent IsNot Nothing If parent.Kind = SyntaxKind.Attribute Then Return DirectCast(parent, AttributeSyntax).Name.Span.Contains(syntax.Position) ElseIf TypeOf parent Is ExpressionSyntax OrElse TypeOf parent Is StatementSyntax Then Exit While End If parent = parent.Parent End While Return False End Function Public Shared Function CanPassToParamArray( expression As BoundExpression, targetType As TypeSymbol, <Out()> ByRef outConvKind As KeyValuePair(Of ConversionKind, MethodSymbol), binder As Binder, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) As Boolean '§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. outConvKind = Conversions.ClassifyConversion(expression, targetType, binder, useSiteInfo) ' Note, user-defined conversions are acceptable here. If Conversions.IsWideningConversion(outConvKind.Key) Then Return True End If ' Dev10 allows explicitly converted NOTHING as an argument for a ParamArray parameter, ' even if conversion to the array type is narrowing. If IsNothingLiteral(expression) Then Debug.Assert(Conversions.IsNarrowingConversion(outConvKind.Key)) Return True End If Return False End Function ''' <summary> ''' Performs an initial pass through the group of candidates and does ''' the following in the process. ''' 1) Eliminates candidates based on the number of supplied arguments and number of supplied generic type arguments. ''' 2) Adds additional entries for expanded ParamArray forms when applicable. ''' 3) Infers method's generic type arguments if needed. ''' 4) Substitutes method's generic type arguments. ''' 5) Eliminates candidates based on shadowing by signature. ''' This partially takes care of §11.8.1 Overloaded Method Resolution, section 7.1. ''' If M is defined in a more derived type than N, eliminate N from the set. ''' 6) Eliminates candidates with identical virtual signatures by applying various shadowing and ''' tie-breaking rules from §11.8.1 Overloaded Method Resolution, section 7.0 ''' • If M has fewer parameters from an expanded paramarray than N, eliminate N from the set. ''' 7) Takes care of unsupported overloading within the same type for instance methods/properties. ''' ''' Assumptions: ''' 1) Shadowing by name has been already applied. ''' 2) group can include extension methods. ''' 3) group contains original definitions, i.e. method type arguments have not been substituted yet. ''' Exception are extension methods with type parameters substituted based on receiver type rather ''' than based on type arguments supplied at the call site. ''' 4) group contains only accessible candidates. ''' 5) group doesn't contain members involved into unsupported overloading, i.e. differ by casing or custom modifiers only. ''' 6) group does not contain duplicates. ''' 7) All elements of arguments array are Not Nothing, omitted arguments are represented by OmittedArgumentExpression node. ''' </summary> ''' <remarks> ''' This method is destructive to content of the [group] parameter. ''' </remarks> Private Shared Sub CollectOverloadedCandidates( binder As Binder, results As ArrayBuilder(Of CandidateAnalysisResult), group As ArrayBuilder(Of Candidate), typeArguments As ImmutableArray(Of TypeSymbol), arguments As ImmutableArray(Of BoundExpression), argumentNames As ImmutableArray(Of String), someCandidatesHaveOverloadResolutionPriority As Boolean, delegateReturnType As TypeSymbol, delegateReturnTypeReferenceBoundNode As BoundNode, includeEliminatedCandidates As Boolean, isQueryOperatorInvocation As Boolean, forceExpandedForm As Boolean, <[In](), Out()> ByRef asyncLambdaSubToFunctionMismatch As HashSet(Of BoundExpression), <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) Debug.Assert(results IsNot Nothing) Debug.Assert(argumentNames.IsDefault OrElse (argumentNames.Length > 0 AndAlso argumentNames.Length = arguments.Length)) Dim quickInfo = ArrayBuilder(Of QuickApplicabilityInfo).GetInstance() Dim sourceModule As ModuleSymbol = binder.SourceModule For i As Integer = 0 To group.Count - 1 If group(i) Is Nothing Then Continue For End If Dim info As QuickApplicabilityInfo = DoQuickApplicabilityCheck(group(i), typeArguments, arguments, isQueryOperatorInvocation, forceExpandedForm, useSiteInfo) If info.Candidate Is Nothing Then Continue For End If If info.Candidate.UnderlyingSymbol.ContainingModule Is sourceModule OrElse info.Candidate.IsExtensionMethod Then CollectOverloadedCandidate(results, info, typeArguments, arguments, argumentNames, someCandidatesHaveOverloadResolutionPriority, delegateReturnType, delegateReturnTypeReferenceBoundNode, includeEliminatedCandidates, binder, asyncLambdaSubToFunctionMismatch, useSiteInfo) Continue For End If ' Deal with VB-illegal overloading in imported types. ' We are trying to avoid doing signature comparison as much as possible and limit them to ' cases when at least one candidate is applicable based on the quick applicability check. ' Similar code exists in overriding checks in OverrideHidingHelper.RemoveMembersWithConflictingAccessibility. Dim container As Symbol = info.Candidate.UnderlyingSymbol.ContainingSymbol ' If there are more candidates from this type, collect all of them in quickInfo array, ' but keep the applicable candidates at the beginning quickInfo.Clear() quickInfo.Add(info) Dim applicableCount As Integer = If(info.State = CandidateAnalysisResultState.Applicable, 1, 0) For j As Integer = i + 1 To group.Count - 1 If group(j) Is Nothing OrElse group(j).IsExtensionMethod Then ' VS2013 ignores illegal overloading for extension methods Continue For End If If container = group(j).UnderlyingSymbol.ContainingSymbol Then info = DoQuickApplicabilityCheck(group(j), typeArguments, arguments, isQueryOperatorInvocation, forceExpandedForm, useSiteInfo) group(j) = Nothing If info.Candidate Is Nothing Then Continue For End If ' Keep applicable candidates at the beginning. If info.State <> CandidateAnalysisResultState.Applicable Then quickInfo.Add(info) ElseIf applicableCount = quickInfo.Count Then quickInfo.Add(info) applicableCount += 1 Else quickInfo.Add(quickInfo(applicableCount)) quickInfo(applicableCount) = info applicableCount += 1 End If End If Next ' Now see if any candidates are ambiguous or lose against other candidates in the quickInfo array. ' This loop is destructive to the content of the quickInfo, some applicable candidates could be replaced with ' a "better" candidate, even though that candidate is not applicable, "losers" are deleted, etc. For k As Integer = 0 To If(applicableCount > 0 OrElse Not includeEliminatedCandidates, applicableCount, quickInfo.Count) - 1 info = quickInfo(k) If info.Candidate Is Nothing OrElse info.State = CandidateAnalysisResultState.Ambiguous Then Continue For End If #If DEBUG Then Dim isExtensionMethod As Boolean = info.Candidate.IsExtensionMethod #End If Dim firstSymbol As Symbol = info.Candidate.UnderlyingSymbol.OriginalDefinition If firstSymbol.IsReducedExtensionMethod() Then firstSymbol = DirectCast(firstSymbol, MethodSymbol).ReducedFrom End If For l As Integer = k + 1 To quickInfo.Count - 1 Dim info2 As QuickApplicabilityInfo = quickInfo(l) If info2.Candidate Is Nothing OrElse info2.State = CandidateAnalysisResultState.Ambiguous Then Continue For End If #If DEBUG Then Debug.Assert(isExtensionMethod = info2.Candidate.IsExtensionMethod) #End If Dim secondSymbol As Symbol = info2.Candidate.UnderlyingSymbol.OriginalDefinition If secondSymbol.IsReducedExtensionMethod() Then secondSymbol = DirectCast(secondSymbol, MethodSymbol).ReducedFrom End If ' The following check should be similar to the one performed by SourceNamedTypeSymbol.CheckForOverloadsErrors ' However, we explicitly ignore custom modifiers here, since this part is NYI for SourceNamedTypeSymbol. Const significantDifferences As SymbolComparisonResults = SymbolComparisonResults.AllMismatches And Not SymbolComparisonResults.MismatchesForConflictingMethods Dim comparisonResults As SymbolComparisonResults = OverrideHidingHelper.DetailedSignatureCompare( firstSymbol, secondSymbol, significantDifferences, significantDifferences) ' Signature must be considered equal following VB rules. If comparisonResults = 0 Then Dim accessibilityCmp As Integer = LookupResult.CompareAccessibilityOfSymbolsConflictingInSameContainer(firstSymbol, secondSymbol) If accessibilityCmp > 0 Then ' first wins quickInfo(l) = Nothing ElseIf accessibilityCmp < 0 Then ' second wins quickInfo(k) = info2 quickInfo(l) = Nothing firstSymbol = secondSymbol info = info2 Else Debug.Assert(accessibilityCmp = 0) info = New QuickApplicabilityInfo(info.Candidate, CandidateAnalysisResultState.Ambiguous) quickInfo(k) = info quickInfo(l) = New QuickApplicabilityInfo(info2.Candidate, CandidateAnalysisResultState.Ambiguous) End If End If Next If info.State <> CandidateAnalysisResultState.Ambiguous Then CollectOverloadedCandidate(results, info, typeArguments, arguments, argumentNames, someCandidatesHaveOverloadResolutionPriority, delegateReturnType, delegateReturnTypeReferenceBoundNode, includeEliminatedCandidates, binder, asyncLambdaSubToFunctionMismatch, useSiteInfo) ElseIf includeEliminatedCandidates Then CollectOverloadedCandidate(results, info, typeArguments, arguments, argumentNames, someCandidatesHaveOverloadResolutionPriority, delegateReturnType, delegateReturnTypeReferenceBoundNode, includeEliminatedCandidates, binder, asyncLambdaSubToFunctionMismatch, useSiteInfo) For l As Integer = k + 1 To quickInfo.Count - 1 Dim info2 As QuickApplicabilityInfo = quickInfo(l) If info2.Candidate IsNot Nothing AndAlso info2.State = CandidateAnalysisResultState.Ambiguous Then quickInfo(l) = Nothing CollectOverloadedCandidate(results, info2, typeArguments, arguments, argumentNames, someCandidatesHaveOverloadResolutionPriority, delegateReturnType, delegateReturnTypeReferenceBoundNode, includeEliminatedCandidates, binder, asyncLambdaSubToFunctionMismatch, useSiteInfo) End If Next End If Next Next quickInfo.Free() #If DEBUG Then group.Clear() #End If End Sub Private Structure QuickApplicabilityInfo Public ReadOnly Candidate As Candidate Public ReadOnly State As CandidateAnalysisResultState Public ReadOnly AppliesToNormalForm As Boolean Public ReadOnly AppliesToParamArrayForm As Boolean Public Sub New( candidate As Candidate, state As CandidateAnalysisResultState, Optional appliesToNormalForm As Boolean = True, Optional appliesToParamArrayForm As Boolean = True ) Debug.Assert(candidate IsNot Nothing) Debug.Assert(appliesToNormalForm OrElse appliesToParamArrayForm) Me.Candidate = candidate Me.State = state Me.AppliesToNormalForm = appliesToNormalForm Me.AppliesToParamArrayForm = appliesToParamArrayForm End Sub End Structure Private Shared Function DoQuickApplicabilityCheck( candidate As Candidate, typeArguments As ImmutableArray(Of TypeSymbol), arguments As ImmutableArray(Of BoundExpression), isQueryOperatorInvocation As Boolean, forceExpandedForm As Boolean, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) As QuickApplicabilityInfo If isQueryOperatorInvocation AndAlso DirectCast(candidate.UnderlyingSymbol, MethodSymbol).IsSub Then ' Subs are never considered as candidates for Query Operators, but method group might have subs in it. Return Nothing End If If candidate.UnderlyingSymbol.HasUnsupportedMetadata Then Return New QuickApplicabilityInfo(candidate, CandidateAnalysisResultState.HasUnsupportedMetadata) End If ' If type arguments have been supplied, eliminate procedures that don't have an ' appropriate number of type parameters. '§11.8.2 Applicable Methods 'Section 4. ' If type arguments have been specified, they are matched against the type parameter list. ' If the two lists do not have the same number of elements, the method is not applicable, ' unless the type argument list is empty. If typeArguments.Length > 0 AndAlso candidate.Arity <> typeArguments.Length Then Return New QuickApplicabilityInfo(candidate, CandidateAnalysisResultState.BadGenericArity) End If ' Eliminate procedures that cannot accept the number of supplied arguments. Dim requiredCount As Integer Dim maxCount As Integer Dim hasParamArray As Boolean candidate.GetAllParameterCounts(requiredCount, maxCount, hasParamArray) '§11.8.2 Applicable Methods '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 single argument expression 'matches a paramarray parameter and the type of the argument expression is convertible to both the type of 'the paramarray parameter and the paramarray element type, the method is applicable in both its expanded 'and unexpanded forms, with two exceptions. 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. If the argument 'expression is the literal Nothing, then the method is only applicable in its unexpanded form. If isQueryOperatorInvocation Then ' Query operators require exact match for argument count. If arguments.Length <> maxCount Then Return New QuickApplicabilityInfo(candidate, CandidateAnalysisResultState.ArgumentCountMismatch, True, False) End If ElseIf arguments.Length < requiredCount OrElse (Not hasParamArray AndAlso arguments.Length > maxCount) Then Return New QuickApplicabilityInfo(candidate, CandidateAnalysisResultState.ArgumentCountMismatch, Not hasParamArray, hasParamArray) End If Dim candidateUseSiteInfo As UseSiteInfo(Of AssemblySymbol) = candidate.UnderlyingSymbol.GetUseSiteInfo() useSiteInfo.Add(candidateUseSiteInfo) If candidateUseSiteInfo.DiagnosticInfo IsNot Nothing Then Return New QuickApplicabilityInfo(candidate, CandidateAnalysisResultState.HasUseSiteError) End If ' A method with a paramarray can be considered in two forms: in an ' expanded form or in an unexpanded form (i.e. as if the paramarray ' decoration was not specified). It can apply in both forms, as ' in the case of passing Object() to ParamArray x As Object() (because ' Object() converts to both Object() and Object). ' Does the method apply in its unexpanded form? This can only happen if ' either there is no paramarray or if the argument count matches exactly ' (if it's less, then the paramarray is expanded to nothing, if it's more, ' it's expanded to one or more parameters). Dim applicableInNormalForm As Boolean = False Dim applicableInParamArrayForm As Boolean = False If Not hasParamArray OrElse (arguments.Length = maxCount AndAlso Not forceExpandedForm) Then applicableInNormalForm = True End If ' How about it's expanded form? It always applies if there's a paramarray. If hasParamArray AndAlso Not isQueryOperatorInvocation Then applicableInParamArrayForm = True End If Return New QuickApplicabilityInfo(candidate, CandidateAnalysisResultState.Applicable, applicableInNormalForm, applicableInParamArrayForm) End Function Private Shared Sub CollectOverloadedCandidate( results As ArrayBuilder(Of CandidateAnalysisResult), candidate As QuickApplicabilityInfo, typeArguments As ImmutableArray(Of TypeSymbol), arguments As ImmutableArray(Of BoundExpression), argumentNames As ImmutableArray(Of String), someCandidatesHaveOverloadResolutionPriority As Boolean, delegateReturnType As TypeSymbol, delegateReturnTypeReferenceBoundNode As BoundNode, includeEliminatedCandidates As Boolean, binder As Binder, <[In](), Out()> ByRef asyncLambdaSubToFunctionMismatch As HashSet(Of BoundExpression), <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) Select Case candidate.State Case CandidateAnalysisResultState.HasUnsupportedMetadata If includeEliminatedCandidates Then results.Add(New CandidateAnalysisResult(candidate.Candidate, CandidateAnalysisResultState.HasUnsupportedMetadata)) End If Case CandidateAnalysisResultState.HasUseSiteError If includeEliminatedCandidates Then results.Add(New CandidateAnalysisResult(candidate.Candidate, CandidateAnalysisResultState.HasUseSiteError)) End If Case CandidateAnalysisResultState.BadGenericArity If includeEliminatedCandidates Then results.Add(New CandidateAnalysisResult(candidate.Candidate, CandidateAnalysisResultState.BadGenericArity)) End If Case CandidateAnalysisResultState.ArgumentCountMismatch Debug.Assert(candidate.AppliesToNormalForm <> candidate.AppliesToParamArrayForm) If includeEliminatedCandidates Then Dim candidateAnalysis As New CandidateAnalysisResult(ConstructIfNeedTo(candidate.Candidate, typeArguments), CandidateAnalysisResultState.ArgumentCountMismatch) If candidate.AppliesToParamArrayForm Then candidateAnalysis.SetIsExpandedParamArrayForm() End If results.Add(candidateAnalysis) End If Case CandidateAnalysisResultState.Applicable Dim candidateAnalysis As CandidateAnalysisResult If typeArguments.Length > 0 Then candidateAnalysis = New CandidateAnalysisResult(candidate.Candidate.Construct(typeArguments)) Else candidateAnalysis = New CandidateAnalysisResult(candidate.Candidate) End If #If DEBUG Then Dim triedToAddSomething As Boolean = False #End If If candidate.AppliesToNormalForm Then #If DEBUG Then triedToAddSomething = True #End If InferTypeArgumentsIfNeedToAndCombineWithExistingCandidates(results, candidateAnalysis, typeArguments, arguments, argumentNames, someCandidatesHaveOverloadResolutionPriority, delegateReturnType, delegateReturnTypeReferenceBoundNode, binder, asyncLambdaSubToFunctionMismatch, useSiteInfo) End If ' How about it's expanded form? It always applies if there's a paramarray. If candidate.AppliesToParamArrayForm Then #If DEBUG Then triedToAddSomething = True #End If candidateAnalysis.SetIsExpandedParamArrayForm() candidateAnalysis.ExpandedParamArrayArgumentsUsed = Math.Max(arguments.Length - candidate.Candidate.ParameterCount + 1, 0) InferTypeArgumentsIfNeedToAndCombineWithExistingCandidates(results, candidateAnalysis, typeArguments, arguments, argumentNames, someCandidatesHaveOverloadResolutionPriority, delegateReturnType, delegateReturnTypeReferenceBoundNode, binder, asyncLambdaSubToFunctionMismatch, useSiteInfo) End If #If DEBUG Then Debug.Assert(triedToAddSomething) #End If Case CandidateAnalysisResultState.Ambiguous If includeEliminatedCandidates Then results.Add(New CandidateAnalysisResult(candidate.Candidate, CandidateAnalysisResultState.Ambiguous)) End If Case Else Throw ExceptionUtilities.UnexpectedValue(candidate.State) End Select End Sub Private Shared Sub InferTypeArgumentsIfNeedToAndCombineWithExistingCandidates( results As ArrayBuilder(Of CandidateAnalysisResult), newCandidate As CandidateAnalysisResult, typeArguments As ImmutableArray(Of TypeSymbol), arguments As ImmutableArray(Of BoundExpression), argumentNames As ImmutableArray(Of String), someCandidatesHaveOverloadResolutionPriority As Boolean, delegateReturnType As TypeSymbol, delegateReturnTypeReferenceBoundNode As BoundNode, binder As Binder, <[In](), Out()> ByRef asyncLambdaSubToFunctionMismatch As HashSet(Of BoundExpression), <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) If typeArguments.Length = 0 AndAlso newCandidate.Candidate.Arity > 0 Then '§11.8.2 Applicable Methods 'Section 4. 'If the type argument list is empty, type inferencing is used to try and infer the type argument list. 'If type inferencing fails, the method is not applicable. Otherwise, the type arguments are filled 'in the place of the type parameters in the signature. If Not InferTypeArguments(newCandidate, arguments, argumentNames, delegateReturnType, delegateReturnTypeReferenceBoundNode, asyncLambdaSubToFunctionMismatch, binder, useSiteInfo) Then Debug.Assert(newCandidate.State <> CandidateAnalysisResultState.Applicable) results.Add(newCandidate) Return End If End If CombineCandidates(results, newCandidate, arguments.Length, argumentNames, someCandidatesHaveOverloadResolutionPriority, useSiteInfo) End Sub ''' <summary> ''' Combine new candidate with the list of existing candidates, applying various shadowing and ''' tie-breaking rules. New candidate may or may not be added to the result, some ''' existing candidates may be removed from the result. ''' </summary> Private Shared Sub CombineCandidates( results As ArrayBuilder(Of CandidateAnalysisResult), newCandidate As CandidateAnalysisResult, argumentCount As Integer, argumentNames As ImmutableArray(Of String), someCandidatesHaveOverloadResolutionPriority As Boolean, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) Debug.Assert(newCandidate.State = CandidateAnalysisResultState.Applicable) Dim operatorResolution As Boolean = newCandidate.Candidate.IsOperator Debug.Assert(newCandidate.Candidate.ParameterCount >= argumentCount OrElse newCandidate.IsExpandedParamArrayForm) Debug.Assert(argumentNames.IsDefault OrElse argumentNames.Length > 0) Debug.Assert(Not operatorResolution OrElse argumentNames.IsDefault) Dim i As Integer = 0 While i < results.Count Dim existingCandidate As CandidateAnalysisResult = results(i) ' Skip over some eliminated candidates, which we will be unable to match signature against. If existingCandidate.State = CandidateAnalysisResultState.ArgumentCountMismatch OrElse existingCandidate.State = CandidateAnalysisResultState.BadGenericArity OrElse existingCandidate.State = CandidateAnalysisResultState.Ambiguous Then GoTo ContinueCandidatesLoop End If ' Candidate can't hide another form of itself If existingCandidate.Candidate Is newCandidate.Candidate Then Debug.Assert(Not operatorResolution) GoTo ContinueCandidatesLoop End If Dim existingWins As Boolean = False Dim newWins As Boolean = False ' An overriding method hides the methods it overrides. ' In particular, this rule takes care of bug VSWhidbey #385900. Where type argument inference fails ' for an overriding method due to named argument name mismatch, but succeeds for the overridden method ' from base (the overridden method uses parameter name matching the named argument name). At the end, ' however, the overriding method is called, even though it doesn't have parameter with matching name. ' Also helps with methods overridden by restricted types (TypedReference, etc.), ShadowBasedOnReceiverType ' doesn't do the job for them because it relies on Conversions.ClassifyDirectCastConversion, which ' disallows boxing conversion for restricted types. If Not operatorResolution AndAlso ShadowBasedOnOverriding(existingCandidate, newCandidate, existingWins, newWins) Then GoTo DeterminedTheWinner End If If existingCandidate.State = CandidateAnalysisResultState.TypeInferenceFailed OrElse existingCandidate.SomeInferenceFailed OrElse existingCandidate.State = CandidateAnalysisResultState.HasUseSiteError OrElse existingCandidate.State = CandidateAnalysisResultState.HasUnsupportedMetadata Then ' Won't be able to match signature. GoTo ContinueCandidatesLoop End If ' It looks like the following code is applying some tie-breaking rules from section 7 of ' §11.8.1 Overloaded Method Resolution, but not all of them and even skips ParamArrays tie-breaking ' rule in some scenarios. I couldn't find an explanation of this behavior in the spec and ' simply tried to keep this code close to Dev10. ' Spec says that the tie-breaking rules should be applied only for members equally applicable to the argument list. ' [§11.8.1.1 Applicability] defines equally applicable members as follows: ' A member M is considered equally applicable as N if ' 1) their signatures are the same or ' 2) if each parameter type in M is the same as the corresponding parameter type in N. ' We can always check if signature is the same, but we cannot check the second condition in presence ' of named arguments because for them we don't know yet which parameter in M corresponds to which ' parameter in N. Debug.Assert(existingCandidate.Candidate.ParameterCount >= argumentCount OrElse existingCandidate.IsExpandedParamArrayForm) If argumentNames.IsDefault Then If Not CombineCandidatesCompareVirtualSignature(newCandidate, existingCandidate, argumentCount) Then ' Signatures are different, shadowing rules do not apply GoTo ContinueCandidatesLoop End If Else Debug.Assert(Not operatorResolution) End If Dim signatureMatch As Boolean ' Compare complete signature, with no regard to arguments If existingCandidate.Candidate.ParameterCount <> newCandidate.Candidate.ParameterCount Then Debug.Assert(Not operatorResolution) signatureMatch = False ElseIf operatorResolution Then Debug.Assert(argumentCount = existingCandidate.Candidate.ParameterCount) Debug.Assert(argumentNames.IsDefault) ' We matched the virtual signature above signatureMatch = True ' Not lifted operators are preferred over lifted. If ShadowBasedOnLiftedState(existingCandidate, newCandidate, existingWins, newWins) Then If someCandidatesHaveOverloadResolutionPriority Then GoTo ContinueCandidatesLoop Else GoTo DeterminedTheWinner End If End If Else signatureMatch = CombineCandidatesCompareDeclaredSignature(newCandidate, existingCandidate) End If If Not argumentNames.IsDefault AndAlso Not signatureMatch Then ' Signatures are different, shadowing rules do not apply GoTo ContinueCandidatesLoop End If If Not signatureMatch Then Debug.Assert(argumentNames.IsDefault) ' We matched the virtual signature above ' If we have gotten to this point it means that the 2 procedures have equal specificity, ' but signatures that do not match exactly (after generic substitution). This ' implies that we are dealing with differences in shape due to param arrays ' or optional arguments. ' So we look and see if one procedure maps fewer arguments to the ' param array than the other. The one using more, is then shadowed by the one using less. '• If M has fewer parameters from an expanded paramarray than N, eliminate N from the set. If Not someCandidatesHaveOverloadResolutionPriority AndAlso ShadowBasedOnParamArrayUsage(existingCandidate, newCandidate, existingWins, newWins) Then GoTo DeterminedTheWinner End If Else ' The signatures of the two methods match (after generic parameter substitution). ' This means that param array shadowing doesn't come into play. ' !!! Why? Where is this mentioned in the spec? End If Debug.Assert(argumentNames.IsDefault OrElse signatureMatch) ' In presence of named arguments, the following shadowing rules ' cannot be applied if any candidate is extension method because ' full signature match doesn't guarantee equal applicability (in presence of named arguments) ' and instance methods hide by signature regardless applicability rules do not apply to extension methods. If argumentNames.IsDefault OrElse Not (existingCandidate.Candidate.IsExtensionMethod OrElse newCandidate.Candidate.IsExtensionMethod) Then '7.1. If M is defined in a more derived type than N, eliminate N from the set. ' This rule also applies to the types that extension methods are defined on. '7.2. If M and N are extension methods and the target type of M is a class or ' structure and the target type of N is an interface, eliminate N from the set. If (Not someCandidatesHaveOverloadResolutionPriority OrElse (signatureMatch AndAlso Not (existingCandidate.Candidate.IsExtensionMethod OrElse newCandidate.Candidate.IsExtensionMethod))) AndAlso ShadowBasedOnReceiverType(existingCandidate, newCandidate, existingWins, newWins, useSiteInfo) Then GoTo DeterminedTheWinner End If '7.3. If M and N are extension methods and the target type of M has fewer type ' parameters than the target type of N, eliminate N from the set. ' !!! Note that spec talks about "fewer type parameters", but it is not really about count. ' !!! It is about one refers to a type parameter and the other one doesn't. If Not someCandidatesHaveOverloadResolutionPriority AndAlso ShadowBasedOnExtensionMethodTargetTypeGenericity(existingCandidate, newCandidate, existingWins, newWins) Then GoTo DeterminedTheWinner End If End If DeterminedTheWinner: Debug.Assert(Not existingWins OrElse Not newWins) ' Both cannot win! If newWins Then ' Remove existing results.RemoveAt(i) ' We should continue the loop because at least with ' extension methods in the picture, there could be other ' winners and losers in the results. ' Since we removed the element, we should bypass index increment. Continue While ElseIf existingWins Then ' New candidate lost, shouldn't add it. Return End If ContinueCandidatesLoop: i += 1 End While results.Add(newCandidate) End Sub Private Shared Function CombineCandidatesCompareVirtualSignature(newCandidate As CandidateAnalysisResult, existingCandidate As CandidateAnalysisResult, argumentCount As Integer) As Boolean Dim existingParamIndex As Integer = 0 Dim newParamIndex As Integer = 0 'CONSIDER: Can we somehow merge this with the complete signature comparison? For j As Integer = 0 To argumentCount - 1 Step 1 Dim existingType As TypeSymbol = GetParameterTypeFromVirtualSignature(existingCandidate, existingParamIndex) Dim newType As TypeSymbol = GetParameterTypeFromVirtualSignature(newCandidate, newParamIndex) If Not existingType.IsSameTypeIgnoringAll(newType) Then ' Signatures are different, shadowing rules do not apply Return False End If ' Advance to the next parameter in the existing candidate, ' unless we are on the expanded ParamArray parameter. AdvanceParameterInVirtualSignature(existingCandidate, existingParamIndex) ' Advance to the next parameter in the new candidate, ' unless we are on the expanded ParamArray parameter. AdvanceParameterInVirtualSignature(newCandidate, newParamIndex) Next Return True End Function Private Shared Function CombineCandidatesCompareDeclaredSignature(newCandidate As CandidateAnalysisResult, existingCandidate As CandidateAnalysisResult) As Boolean For j As Integer = 0 To existingCandidate.Candidate.ParameterCount - 1 Step 1 Dim existingType As TypeSymbol = existingCandidate.Candidate.Parameters(j).Type Dim newType As TypeSymbol = newCandidate.Candidate.Parameters(j).Type If Not existingType.IsSameTypeIgnoringAll(newType) Then Return False End If Next Return True End Function Private Shared Function ShadowBasedOnLiftedState( existingCandidate As CandidateAnalysisResult, newCandidate As CandidateAnalysisResult, ByRef existingWins As Boolean, ByRef newWins As Boolean ) As Boolean If existingCandidate.Candidate.IsLifted Then If Not newCandidate.Candidate.IsLifted Then newWins = True Return True End If ElseIf newCandidate.Candidate.IsLifted Then Debug.Assert(Not existingCandidate.Candidate.IsLifted) existingWins = True Return True End If Return False End Function Private Shared Function ShadowBasedOnOverriding( existingCandidate As CandidateAnalysisResult, newCandidate As CandidateAnalysisResult, ByRef existingWins As Boolean, ByRef newWins As Boolean ) As Boolean Dim existingSymbol As Symbol = existingCandidate.Candidate.UnderlyingSymbol Dim newSymbol As Symbol = newCandidate.Candidate.UnderlyingSymbol Dim existingType As NamedTypeSymbol = existingSymbol.ContainingType Dim newType As NamedTypeSymbol = newSymbol.ContainingType ' Optimization: We will rely on ShadowBasedOnReceiverType to give us the ' same effect later on for cases when existingCandidate is ' applicable and neither candidate is from restricted type. Dim existingIsApplicable As Boolean = (existingCandidate.State = CandidateAnalysisResultState.Applicable) If existingIsApplicable AndAlso Not existingType.IsRestrictedType() AndAlso Not newType.IsRestrictedType() Then Return False End If ' Optimization: symbols from the same type can't override each other. ' ShadowBasedOnReceiverType If existingType.OriginalDefinition IsNot newType.OriginalDefinition Then If newCandidate.Candidate.IsOverriddenBy(existingSymbol) Then existingWins = True Return True ElseIf existingIsApplicable AndAlso existingCandidate.Candidate.IsOverriddenBy(newSymbol) Then newWins = True Return True End If End If Return False End Function ''' <summary> ''' Implements shadowing based on ''' §11.8.1 Overloaded Method Resolution. ''' 7.5. If M is not an extension method and N is, eliminate N from the set. ''' 7.6. If M and N are extension methods and M was found before N, eliminate N from the set. ''' </summary> Private Shared Function ShadowBasedOnExtensionVsInstanceAndPrecedence( left As CandidateAnalysisResult, right As CandidateAnalysisResult, ByRef leftWins As Boolean, ByRef rightWins As Boolean ) As Boolean If left.Candidate.IsExtensionMethod Then If Not right.Candidate.IsExtensionMethod Then '7.5. rightWins = True Return True Else ' Both are extensions If left.Candidate.PrecedenceLevel < right.Candidate.PrecedenceLevel Then '7.6. leftWins = True Return True ElseIf left.Candidate.PrecedenceLevel > right.Candidate.PrecedenceLevel Then '7.6. rightWins = True Return True End If End If ElseIf right.Candidate.IsExtensionMethod Then '7.5. leftWins = True Return True End If Return False End Function ''' <summary> ''' Implements shadowing based on ''' §11.8.1 Overloaded Method Resolution. ''' 7.4. If M is less generic than N, eliminate N from the set. ''' </summary> Private Shared Function ShadowBasedOnGenericity( left As CandidateAnalysisResult, right As CandidateAnalysisResult, ByRef leftWins As Boolean, ByRef rightWins As Boolean, arguments As ImmutableArray(Of BoundExpression), binder As Binder ) As Boolean ' §11.8.1.2 Genericity ' A member M is determined to be less generic than a member N as follows: ' ' 1. If, for each pair of matching parameters Mj and Nj, Mj is less or equally generic than Nj ' with respect to type parameters on the method, and at least one Mj is less generic with ' respect to type parameters on the method. ' 2. Otherwise, if for each pair of matching parameters Mj and Nj, Mj is less or equally generic ' than Nj with respect to type parameters on the type, and at least one Mj is less generic with ' respect to type parameters on the type, then M is less generic than N. ' ' A parameter M is considered to be equally generic to a parameter N if their types Mt and Nt ' both refer to type parameters or both don't refer to type parameters. M is considered to be less ' generic than N if Mt does not refer to a type parameter and Nt does. ' ' Extension method type parameters that were fixed during currying are considered type parameters on the type, ' not type parameters on the method. ' At the beginning we will track both method and type type parameters. Dim track As TypeParameterKind = TypeParameterKind.Both If Not (left.Candidate.IsGeneric OrElse right.Candidate.IsGeneric) Then track = track And (Not TypeParameterKind.Method) End If If Not ((left.Candidate.UnderlyingSymbol.ContainingType.IsOrInGenericType() OrElse (left.Candidate.IsExtensionMethod AndAlso Not left.Candidate.FixedTypeParameters.IsNull)) OrElse (right.Candidate.UnderlyingSymbol.ContainingType.IsOrInGenericType() OrElse (right.Candidate.IsExtensionMethod AndAlso Not right.Candidate.FixedTypeParameters.IsNull))) Then track = track And (Not TypeParameterKind.Type) End If If track = TypeParameterKind.None Then Return False ' There is no winner. End If #If DEBUG Then Dim saveTrack = track #End If Dim leftHasLeastGenericParameterAgainstMethod As Boolean = False Dim leftHasLeastGenericParameterAgainstType As Boolean = False Dim rightHasLeastGenericParameterAgainstMethod As Boolean = False Dim rightHasLeastGenericParameterAgainstType As Boolean = False Dim leftParamIndex As Integer = 0 Dim rightParamIndex As Integer = 0 For i = 0 To arguments.Length - 1 Step 1 Dim leftParamType As TypeSymbol Dim leftParamTypeForGenericityCheck As TypeSymbol = Nothing Debug.Assert(left.ArgsToParamsOpt.IsDefault = right.ArgsToParamsOpt.IsDefault) If left.ArgsToParamsOpt.IsDefault Then leftParamType = GetParameterTypeFromVirtualSignature(left, leftParamIndex, leftParamTypeForGenericityCheck) AdvanceParameterInVirtualSignature(left, leftParamIndex) Else leftParamType = GetParameterTypeFromVirtualSignature(left, left.ArgsToParamsOpt(i), leftParamTypeForGenericityCheck) End If Dim rightParamType As TypeSymbol Dim rightParamTypeForGenericityCheck As TypeSymbol = Nothing If right.ArgsToParamsOpt.IsDefault Then rightParamType = GetParameterTypeFromVirtualSignature(right, rightParamIndex, rightParamTypeForGenericityCheck) AdvanceParameterInVirtualSignature(right, rightParamIndex) Else rightParamType = GetParameterTypeFromVirtualSignature(right, right.ArgsToParamsOpt(i), rightParamTypeForGenericityCheck) End If ' Parameters matching omitted arguments do not participate. If arguments(i).Kind = BoundKind.OmittedArgument Then Continue For End If If SignatureMismatchForThePurposeOfShadowingBasedOnGenericity(leftParamType, rightParamType, arguments(i), binder) Then Return False End If Dim leftRefersTo As TypeParameterKind = DetectReferencesToGenericParameters(leftParamTypeForGenericityCheck, track, left.Candidate.FixedTypeParameters) Dim rightRefersTo As TypeParameterKind = DetectReferencesToGenericParameters(rightParamTypeForGenericityCheck, track, right.Candidate.FixedTypeParameters) ' Still looking for less generic with respect to type parameters on the method. If (track And TypeParameterKind.Method) <> 0 Then If (leftRefersTo And TypeParameterKind.Method) = 0 Then If (rightRefersTo And TypeParameterKind.Method) <> 0 Then leftHasLeastGenericParameterAgainstMethod = True End If ElseIf (rightRefersTo And TypeParameterKind.Method) = 0 Then rightHasLeastGenericParameterAgainstMethod = True End If ' If both won at least once, neither candidate is less generic with respect to type parameters on the method. ' Stop checking for this. If leftHasLeastGenericParameterAgainstMethod AndAlso rightHasLeastGenericParameterAgainstMethod Then track = track And (Not TypeParameterKind.Method) End If End If ' Still looking for less generic with respect to type parameters on the type. If (track And TypeParameterKind.Type) <> 0 Then If (leftRefersTo And TypeParameterKind.Type) = 0 Then If (rightRefersTo And TypeParameterKind.Type) <> 0 Then leftHasLeastGenericParameterAgainstType = True End If ElseIf (rightRefersTo And TypeParameterKind.Type) = 0 Then rightHasLeastGenericParameterAgainstType = True End If ' If both won at least once, neither candidate is less generic with respect to type parameters on the type. ' Stop checking for this. If leftHasLeastGenericParameterAgainstType AndAlso rightHasLeastGenericParameterAgainstType Then track = track And (Not TypeParameterKind.Type) End If End If ' Are we still looking for a winner? If track = TypeParameterKind.None Then #If DEBUG Then Debug.Assert((saveTrack And TypeParameterKind.Method) = 0 OrElse (leftHasLeastGenericParameterAgainstMethod AndAlso rightHasLeastGenericParameterAgainstMethod)) Debug.Assert((saveTrack And TypeParameterKind.Type) = 0 OrElse (leftHasLeastGenericParameterAgainstType AndAlso rightHasLeastGenericParameterAgainstType)) #End If Return False ' There is no winner. End If Next If leftHasLeastGenericParameterAgainstMethod Then If Not rightHasLeastGenericParameterAgainstMethod Then leftWins = True Return True End If ElseIf rightHasLeastGenericParameterAgainstMethod Then rightWins = True Return True End If If leftHasLeastGenericParameterAgainstType Then If Not rightHasLeastGenericParameterAgainstType Then leftWins = True Return True End If ElseIf rightHasLeastGenericParameterAgainstType Then rightWins = True Return True End If Return False End Function Private Shared Function SignatureMismatchForThePurposeOfShadowingBasedOnGenericity( leftParamType As TypeSymbol, rightParamType As TypeSymbol, argument As BoundExpression, binder As Binder ) As Boolean Debug.Assert(argument.Kind <> BoundKind.OmittedArgument) ' See Semantics::CompareGenericityIsSignatureMismatch in native compiler. If leftParamType.IsSameTypeIgnoringAll(rightParamType) Then Return False Else ' Note: Undocumented rule. ' Different types. We still consider them the same if they are delegates with ' equivalent signatures, after possibly unwrapping Expression(Of D). Dim leftIsExpressionTree As Boolean, rightIsExpressionTree As Boolean Dim leftDelegateType As NamedTypeSymbol = leftParamType.DelegateOrExpressionDelegate(binder, leftIsExpressionTree) Dim rightDelegateType As NamedTypeSymbol = rightParamType.DelegateOrExpressionDelegate(binder, rightIsExpressionTree) ' Native compiler will only compare D1 and D2 for Expression(Of D1) and D2 if the argument is a lambda. It will compare ' Expression(Of D1) and Expression (Of D2) regardless of the argument. If leftDelegateType IsNot Nothing AndAlso rightDelegateType IsNot Nothing AndAlso ((leftIsExpressionTree = rightIsExpressionTree) OrElse argument.IsAnyLambda()) Then Dim leftInvoke = leftDelegateType.DelegateInvokeMethod Dim rightInvoke = rightDelegateType.DelegateInvokeMethod If leftInvoke IsNot Nothing AndAlso rightInvoke IsNot Nothing AndAlso MethodSignatureComparer.ParametersAndReturnTypeSignatureComparer.Equals(leftInvoke, rightInvoke) Then Return False End If End If End If Return True End Function ''' <summary> ''' Implements shadowing based on ''' §11.8.1.3 Depth of genericity ''' </summary> Private Shared Function ShadowBasedOnDepthOfGenericity( left As CandidateAnalysisResult, right As CandidateAnalysisResult, ByRef leftWins As Boolean, ByRef rightWins As Boolean, arguments As ImmutableArray(Of BoundExpression), binder As Binder ) As Boolean ' §11.8.1.3 Depth of Genericity ' A member M is determined to have greater depth of genericity than a member N if, for each pair ' of matching parameters Mj and Nj, Mj has greater or equal depth of genericity than Nj, and at ' least one Mj has greater depth of genericity. Depth of genericity is defined as follows: ' ' 1. Anything other than a type parameter has greater depth of genericity than a type parameter; ' 2. Recursively, a constructed type has greater depth of genericity than another constructed type ' (with the same number of type arguments) if at least one type argument has greater depth ' of genericity and no type argument has less depth than the corresponding type argument in the other. ' 3. An array type has greater depth of genericity than another array type (with the same number ' of dimensions) if the element type of the first has greater depth of genericity than the ' element type of the second. ' ' For example: ' ' Module Test ' Sub f(Of T)(x As Task(Of T)) ' End Sub ' Sub f(Of T)(x As T) ' End Sub ' Sub Main() ' Dim x As Task(Of Integer) = Nothing ' f(x) ' Calls the first overload ' End Sub ' End Module Dim leftParamIndex As Integer = 0 Dim rightParamIndex As Integer = 0 For i = 0 To arguments.Length - 1 Step 1 Dim leftParamType As TypeSymbol Dim leftParamTypeForGenericityCheck As TypeSymbol = Nothing Debug.Assert(left.ArgsToParamsOpt.IsDefault = right.ArgsToParamsOpt.IsDefault) If left.ArgsToParamsOpt.IsDefault Then leftParamType = GetParameterTypeFromVirtualSignature(left, leftParamIndex, leftParamTypeForGenericityCheck) AdvanceParameterInVirtualSignature(left, leftParamIndex) Else leftParamType = GetParameterTypeFromVirtualSignature(left, left.ArgsToParamsOpt(i), leftParamTypeForGenericityCheck) End If Dim rightParamType As TypeSymbol Dim rightParamTypeForGenericityCheck As TypeSymbol = Nothing If right.ArgsToParamsOpt.IsDefault Then rightParamType = GetParameterTypeFromVirtualSignature(right, rightParamIndex, rightParamTypeForGenericityCheck) AdvanceParameterInVirtualSignature(right, rightParamIndex) Else rightParamType = GetParameterTypeFromVirtualSignature(right, right.ArgsToParamsOpt(i), rightParamTypeForGenericityCheck) End If ' Parameters matching omitted arguments do not participate. If arguments(i).Kind = BoundKind.OmittedArgument Then Continue For End If If SignatureMismatchForThePurposeOfShadowingBasedOnGenericity(leftParamType, rightParamType, arguments(i), binder) Then Return False ' no winner if the types of the parameter are different End If Dim leftParamWins As Boolean = False Dim rightParamWins As Boolean = False If CompareParameterTypeGenericDepth(leftParamTypeForGenericityCheck, rightParamTypeForGenericityCheck, leftParamWins, rightParamWins) Then Debug.Assert(leftParamWins <> rightParamWins) If leftParamWins Then If rightWins Then rightWins = False Return False ' both won Else leftWins = True End If Else If leftWins Then leftWins = False Return False ' both won Else rightWins = True End If End If End If Next Debug.Assert(Not leftWins OrElse Not rightWins) Return leftWins OrElse rightWins End Function ''' <summary> ''' ''' </summary> ''' <returns>False if node of candidates wins</returns> Private Shared Function CompareParameterTypeGenericDepth(leftType As TypeSymbol, rightType As TypeSymbol, ByRef leftWins As Boolean, ByRef rightWins As Boolean) As Boolean ' Depth of genericity is defined as follows: ' 1. Anything other than a type parameter has greater depth of genericity than a type parameter; ' 2. Recursively, a constructed type has greater depth of genericity than another constructed ' type (with the same number of type arguments) if at least one type argument has greater ' depth of genericity and no type argument has less depth than the corresponding type ' argument in the other. ' 3. An array type has greater depth of genericity than another array type (with the same number ' of dimensions) if the element type of the first has greater depth of genericity than the ' element type of the second. ' ' For exact rules see Dev11 OverloadResolution.cpp: void Semantics::CompareParameterTypeGenericDepth(...) If leftType Is rightType Then Return False End If If leftType.IsTypeParameter Then If rightType.IsTypeParameter Then ' Both type parameters => no winner Return False Else ' Left is a type parameter, but right is not rightWins = True Return True End If ElseIf rightType.IsTypeParameter Then ' Right is a type parameter, but left is not leftWins = True Return True End If ' None of the two is a type parameter If leftType.IsArrayType AndAlso rightType.IsArrayType Then ' Both are arrays Dim leftArray = DirectCast(leftType, ArrayTypeSymbol) Dim rightArray = DirectCast(rightType, ArrayTypeSymbol) If leftArray.HasSameShapeAs(rightArray) Then Return CompareParameterTypeGenericDepth(leftArray.ElementType, rightArray.ElementType, leftWins, rightWins) End If End If ' Both are generics If leftType.Kind = SymbolKind.NamedType AndAlso rightType.Kind = SymbolKind.NamedType Then Dim leftNamedType = DirectCast(leftType.GetTupleUnderlyingTypeOrSelf(), NamedTypeSymbol) Dim rightNamedType = DirectCast(rightType.GetTupleUnderlyingTypeOrSelf(), NamedTypeSymbol) ' If their arities are equal If leftNamedType.Arity = rightNamedType.Arity Then Dim leftTypeArguments As ImmutableArray(Of TypeSymbol) = leftNamedType.TypeArgumentsNoUseSiteDiagnostics Dim rightTypeArguments As ImmutableArray(Of TypeSymbol) = rightNamedType.TypeArgumentsNoUseSiteDiagnostics For i = 0 To leftTypeArguments.Length - 1 Dim leftArgWins As Boolean = False Dim rightArgWins As Boolean = False If CompareParameterTypeGenericDepth(leftTypeArguments(i), rightTypeArguments(i), leftArgWins, rightArgWins) Then Debug.Assert(leftArgWins <> rightArgWins) If leftArgWins Then If rightWins Then rightWins = False Return False Else leftWins = True End If Else If leftWins Then leftWins = False Return False Else rightWins = True End If End If End If Next Debug.Assert(Not leftWins OrElse Not rightWins) Return leftWins OrElse rightWins End If End If Return False End Function ''' <summary> ''' Implements shadowing based on ''' §11.8.1 Overloaded Method Resolution. ''' 7.3. If M and N are extension methods and the target type of M has fewer type ''' parameters than the target type of N, eliminate N from the set. ''' !!! Note that spec talks about "fewer type parameters", but it is not really about count. ''' !!! It is about one refers to a type parameter and the other one doesn't. ''' </summary> Private Shared Function ShadowBasedOnExtensionMethodTargetTypeGenericity( left As CandidateAnalysisResult, right As CandidateAnalysisResult, ByRef leftWins As Boolean, ByRef rightWins As Boolean ) As Boolean If Not left.Candidate.IsExtensionMethod OrElse Not right.Candidate.IsExtensionMethod Then Return False End If '!!! Note, the spec does not mention this explicitly, but this rule applies only if receiver type '!!! is the same for both methods. If Not left.Candidate.ReceiverType.IsSameTypeIgnoringAll(right.Candidate.ReceiverType) Then Return False End If ' Only interested in method type parameters. Dim leftRefersToATypeParameter = DetectReferencesToGenericParameters(left.Candidate.ReceiverTypeDefinition, TypeParameterKind.Method, BitVector.Null) ' Only interested in method type parameters. Dim rightRefersToATypeParameter = DetectReferencesToGenericParameters(right.Candidate.ReceiverTypeDefinition, TypeParameterKind.Method, BitVector.Null) If (leftRefersToATypeParameter And TypeParameterKind.Method) <> 0 Then If (rightRefersToATypeParameter And TypeParameterKind.Method) = 0 Then rightWins = True Return True End If ElseIf (rightRefersToATypeParameter And TypeParameterKind.Method) <> 0 Then leftWins = True Return True End If Return False End Function <Flags()> Private Enum TypeParameterKind None = 0 Method = 1 << 0 Type = 1 << 1 Both = Method Or Type End Enum Private Shared Function DetectReferencesToGenericParameters( symbol As NamedTypeSymbol, track As TypeParameterKind, methodTypeParametersToTreatAsTypeTypeParameters As BitVector ) As TypeParameterKind Dim result As TypeParameterKind = TypeParameterKind.None Do If symbol Is symbol.OriginalDefinition Then If (track And TypeParameterKind.Type) = 0 Then Return result End If If symbol.Arity > 0 Then Return result Or TypeParameterKind.Type End If Else For Each argument As TypeSymbol In symbol.TypeArgumentsNoUseSiteDiagnostics result = result Or DetectReferencesToGenericParameters(argument, track, methodTypeParametersToTreatAsTypeTypeParameters) If (result And track) = track Then Return result End If Next End If symbol = symbol.ContainingType Loop While symbol IsNot Nothing Return result End Function Private Shared Function DetectReferencesToGenericParameters( symbol As TypeParameterSymbol, track As TypeParameterKind, methodTypeParametersToTreatAsTypeTypeParameters As BitVector ) As TypeParameterKind If symbol.ContainingSymbol.Kind = SymbolKind.NamedType Then If (track And TypeParameterKind.Type) <> 0 Then Return TypeParameterKind.Type End If Else If methodTypeParametersToTreatAsTypeTypeParameters.IsNull OrElse Not methodTypeParametersToTreatAsTypeTypeParameters(symbol.Ordinal) Then If (track And TypeParameterKind.Method) <> 0 Then Return TypeParameterKind.Method End If Else If (track And TypeParameterKind.Type) <> 0 Then Return TypeParameterKind.Type End If End If End If Return TypeParameterKind.None End Function Private Shared Function DetectReferencesToGenericParameters( this As TypeSymbol, track As TypeParameterKind, methodTypeParametersToTreatAsTypeTypeParameters As BitVector ) As TypeParameterKind Select Case this.Kind Case SymbolKind.TypeParameter Return DetectReferencesToGenericParameters(DirectCast(this, TypeParameterSymbol), track, methodTypeParametersToTreatAsTypeTypeParameters) Case SymbolKind.ArrayType Return DetectReferencesToGenericParameters(DirectCast(this, ArrayTypeSymbol).ElementType, track, methodTypeParametersToTreatAsTypeTypeParameters) Case SymbolKind.NamedType, SymbolKind.ErrorType Return DetectReferencesToGenericParameters(DirectCast(this, NamedTypeSymbol), track, methodTypeParametersToTreatAsTypeTypeParameters) Case Else Throw ExceptionUtilities.UnexpectedValue(this.Kind) End Select End Function ''' <summary> ''' Implements shadowing based on ''' §11.8.1 Overloaded Method Resolution. ''' 7.1. If M is defined in a more derived type than N, eliminate N from the set. ''' This rule also applies to the types that extension methods are defined on. ''' 7.2. If M and N are extension methods and the target type of M is a class or ''' structure and the target type of N is an interface, eliminate N from the set. ''' </summary> Private Shared Function ShadowBasedOnReceiverType( left As CandidateAnalysisResult, right As CandidateAnalysisResult, ByRef leftWins As Boolean, ByRef rightWins As Boolean, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) As Boolean Dim leftType = left.Candidate.ReceiverType Dim rightType = right.Candidate.ReceiverType If Not leftType.IsSameTypeIgnoringAll(rightType) Then If DoesReceiverMatchInstance(leftType, rightType, useSiteInfo) Then leftWins = True Return True ElseIf DoesReceiverMatchInstance(rightType, leftType, useSiteInfo) Then rightWins = True Return True End If End If Return False End Function ''' <summary> ''' For a receiver to match an instance, more or less, the type of that instance has to be convertible ''' to the type of the receiver with the same bit-representation (i.e. identity on value-types ''' and reference-convertibility on reference types). ''' Actually, we don't include the reference-convertibilities that seem nonsensical, e.g. enum() to underlyingtype() ''' We do include inheritance, implements and variance conversions amongst others. ''' </summary> Public Shared Function DoesReceiverMatchInstance(instanceType As TypeSymbol, receiverType As TypeSymbol, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)) As Boolean Return Conversions.HasWideningDirectCastConversionButNotEnumTypeConversion(instanceType, receiverType, useSiteInfo) End Function ''' <summary> ''' Implements shadowing based on ''' §11.8.1 Overloaded Method Resolution. ''' • If M has fewer parameters from an expanded paramarray than N, eliminate N from the set. ''' </summary> Private Shared Function ShadowBasedOnParamArrayUsage( left As CandidateAnalysisResult, right As CandidateAnalysisResult, ByRef leftWins As Boolean, ByRef rightWins As Boolean ) As Boolean If left.IsExpandedParamArrayForm Then If right.IsExpandedParamArrayForm Then If left.ExpandedParamArrayArgumentsUsed > right.ExpandedParamArrayArgumentsUsed Then rightWins = True Return True ElseIf left.ExpandedParamArrayArgumentsUsed < right.ExpandedParamArrayArgumentsUsed Then leftWins = True Return True End If Else rightWins = True Return True End If ElseIf right.IsExpandedParamArrayForm Then leftWins = True Return True End If Return False End Function Friend Shared Function GetParameterTypeFromVirtualSignature( ByRef candidate As CandidateAnalysisResult, paramIndex As Integer ) As TypeSymbol Dim paramType As TypeSymbol = candidate.Candidate.Parameters(paramIndex).Type If candidate.IsExpandedParamArrayForm AndAlso paramIndex = candidate.Candidate.ParameterCount - 1 AndAlso paramType.Kind = SymbolKind.ArrayType Then paramType = DirectCast(paramType, ArrayTypeSymbol).ElementType End If Return paramType End Function Private Shared Function GetParameterTypeFromVirtualSignature( ByRef candidate As CandidateAnalysisResult, paramIndex As Integer, ByRef typeForGenericityCheck As TypeSymbol ) As TypeSymbol Dim param As ParameterSymbol = candidate.Candidate.Parameters(paramIndex) Dim paramForGenericityCheck = param.OriginalDefinition If paramForGenericityCheck.ContainingSymbol.Kind = SymbolKind.Method Then Dim method = DirectCast(paramForGenericityCheck.ContainingSymbol, MethodSymbol) If method.IsReducedExtensionMethod Then paramForGenericityCheck = method.ReducedFrom.Parameters(paramIndex + 1) End If End If Dim paramType As TypeSymbol = param.Type typeForGenericityCheck = paramForGenericityCheck.Type If candidate.IsExpandedParamArrayForm AndAlso paramIndex = candidate.Candidate.ParameterCount - 1 AndAlso paramType.Kind = SymbolKind.ArrayType Then paramType = DirectCast(paramType, ArrayTypeSymbol).ElementType typeForGenericityCheck = DirectCast(typeForGenericityCheck, ArrayTypeSymbol).ElementType End If Return paramType End Function Friend Shared Sub AdvanceParameterInVirtualSignature( ByRef candidate As CandidateAnalysisResult, ByRef paramIndex As Integer ) If Not (candidate.IsExpandedParamArrayForm AndAlso paramIndex = candidate.Candidate.ParameterCount - 1) Then paramIndex += 1 End If End Sub Private Shared Function InferTypeArguments( ByRef candidate As CandidateAnalysisResult, arguments As ImmutableArray(Of BoundExpression), argumentNames As ImmutableArray(Of String), delegateReturnType As TypeSymbol, delegateReturnTypeReferenceBoundNode As BoundNode, <[In](), Out()> ByRef asyncLambdaSubToFunctionMismatch As HashSet(Of BoundExpression), binder As Binder, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) As Boolean Dim parameterToArgumentMap As ArrayBuilder(Of Integer) = Nothing Dim paramArrayItems As ArrayBuilder(Of Integer) = Nothing BuildParameterToArgumentMap(candidate, arguments, argumentNames, parameterToArgumentMap, paramArrayItems) If candidate.State = CandidateAnalysisResultState.Applicable Then Dim typeArguments As ImmutableArray(Of TypeSymbol) = Nothing Dim inferenceLevel As TypeArgumentInference.InferenceLevel = TypeArgumentInference.InferenceLevel.None Dim allFailedInferenceIsDueToObject As Boolean = False Dim someInferenceFailed As Boolean = False Dim inferenceErrorReasons As InferenceErrorReasons = InferenceErrorReasons.Other Dim inferredTypeByAssumption As BitVector = Nothing Dim typeArgumentsLocation As ImmutableArray(Of SyntaxNodeOrToken) = Nothing Dim inferenceDiagnosticsBag = BindingDiagnosticBag.GetInstance(withDiagnostics:=True, useSiteInfo.AccumulatesDependencies) If TypeArgumentInference.Infer(DirectCast(candidate.Candidate.UnderlyingSymbol, MethodSymbol), arguments, parameterToArgumentMap, paramArrayItems, delegateReturnType:=delegateReturnType, delegateReturnTypeReferenceBoundNode:=delegateReturnTypeReferenceBoundNode, typeArguments:=typeArguments, inferenceLevel:=inferenceLevel, someInferenceFailed:=someInferenceFailed, allFailedInferenceIsDueToObject:=allFailedInferenceIsDueToObject, inferenceErrorReasons:=inferenceErrorReasons, inferredTypeByAssumption:=inferredTypeByAssumption, typeArgumentsLocation:=typeArgumentsLocation, asyncLambdaSubToFunctionMismatch:=asyncLambdaSubToFunctionMismatch, useSiteInfo:=useSiteInfo, diagnostic:=inferenceDiagnosticsBag) Then candidate.SetInferenceLevel(inferenceLevel) candidate.Candidate = candidate.Candidate.Construct(typeArguments) ' Need check for Option Strict and warn if parameter type is an assumed inferred type. If binder.OptionStrict = OptionStrict.On AndAlso Not inferredTypeByAssumption.IsNull Then For i As Integer = 0 To typeArguments.Length - 1 Step 1 If inferredTypeByAssumption(i) Then Binder.ReportDiagnostic(inferenceDiagnosticsBag, typeArgumentsLocation(i), ERRID.WRN_TypeInferenceAssumed3, candidate.Candidate.TypeParameters(i), DirectCast(candidate.Candidate.UnderlyingSymbol, MethodSymbol).OriginalDefinition, typeArguments(i)) End If Next End If Else candidate.State = CandidateAnalysisResultState.TypeInferenceFailed If someInferenceFailed Then candidate.SetSomeInferenceFailed() End If If allFailedInferenceIsDueToObject Then candidate.SetAllFailedInferenceIsDueToObject() If Not candidate.Candidate.IsExtensionMethod Then candidate.IgnoreExtensionMethods = True End If End If candidate.SetInferenceErrorReasons(inferenceErrorReasons) candidate.NotInferredTypeArguments = BitVector.Create(typeArguments.Length) For i As Integer = 0 To typeArguments.Length - 1 Step 1 If typeArguments(i) Is Nothing Then candidate.NotInferredTypeArguments(i) = True End If Next End If candidate.TypeArgumentInferenceDiagnosticsOpt = inferenceDiagnosticsBag.ToReadOnlyAndFree() Else candidate.SetSomeInferenceFailed() End If If paramArrayItems IsNot Nothing Then paramArrayItems.Free() End If If parameterToArgumentMap IsNot Nothing Then parameterToArgumentMap.Free() End If Return (candidate.State = CandidateAnalysisResultState.Applicable) End Function Private Shared Function ConstructIfNeedTo(candidate As Candidate, typeArguments As ImmutableArray(Of TypeSymbol)) As Candidate If typeArguments.Length > 0 Then Return candidate.Construct(typeArguments) End If Return candidate End Function End Class End Namespace