提交 18e1efe5 编写于 作者: A AlekseyTs

Improve error reporting around lambdas and multiple overloads in VB

Fixes #2604.
上级 0be0b52d
......@@ -1809,14 +1809,12 @@ ProduceBoundNode:
queryMode As Boolean,
callerInfoOpt As VisualBasicSyntaxNode
)
Dim diagnosticInfos = ArrayBuilder(Of DiagnosticInfo).GetInstance(candidates.Count)
Dim diagnosticPerSymbol = ArrayBuilder(Of KeyValuePair(Of Symbol, ImmutableArray(Of Diagnostic))).GetInstance(candidates.Count)
If arguments.IsDefault Then
arguments = ImmutableArray(Of BoundExpression).Empty
End If
' TODO: Collapse the same errors reported for all candidates (see Semantics::ReportOverloadResolutionFailure in Dev10).
For i As Integer = 0 To candidates.Count - 1 Step 1
' See if we need to consider both expanded and unexpanded version of the same method.
......@@ -1846,56 +1844,106 @@ ProduceBoundNode:
callerInfoOpt:=callerInfoOpt,
representCandidateInDiagnosticsOpt:=Nothing)
Dim symbol = candidates(i).Candidate.UnderlyingSymbol
Dim isExtension As Boolean = symbol.IsReducedExtensionMethod()
diagnosticPerSymbol.Add(KeyValuePair.Create(candidates(i).Candidate.UnderlyingSymbol, candidateDiagnostics.ToReadOnlyAndFree()))
Dim sealedCandidateDiagnostics = candidateDiagnostics.ToReadOnlyAndFree()
Next
' When reporting errors for an AddressOf, Dev 10 shows different error messages depending on how many
' errors there are per candidate.
' One narrowing error will be shown like:
' 'Public Sub foo6(p As Integer, p2 As Byte)': Option Strict On disallows implicit conversions from 'Integer' to 'Byte'.
' More than one narrowing issues in the parameters are abbreviated with:
' 'Public Sub foo6(p As Byte, p2 As Byte)': Method does not have a signature compatible with the delegate.
' See if there are errors that are reported for each candidate at the same location within a lambda argument.
' Report them and don't report remaining diagnostics for each symbol separately.
If Not ReportCommonErrorsFromLambdas(diagnosticPerSymbol, arguments, diagnostics) Then
Dim diagnosticInfos = ArrayBuilder(Of DiagnosticInfo).GetInstance(candidates.Count)
If delegateSymbol Is Nothing OrElse Not sealedCandidateDiagnostics.Skip(1).Any() Then
If isExtension Then
For Each iDiagnostic In sealedCandidateDiagnostics
diagnosticInfos.Add(ErrorFactory.ErrorInfo(ERRID.ERR_ExtensionMethodOverloadCandidate3,
For i As Integer = 0 To diagnosticPerSymbol.Count - 1
Dim symbol = diagnosticPerSymbol(i).Key
Dim isExtension As Boolean = symbol.IsReducedExtensionMethod()
Dim sealedCandidateDiagnostics = diagnosticPerSymbol(i).Value
' When reporting errors for an AddressOf, Dev 10 shows different error messages depending on how many
' errors there are per candidate.
' One narrowing error will be shown like:
' 'Public Sub foo6(p As Integer, p2 As Byte)': Option Strict On disallows implicit conversions from 'Integer' to 'Byte'.
' More than one narrowing issues in the parameters are abbreviated with:
' 'Public Sub foo6(p As Byte, p2 As Byte)': Method does not have a signature compatible with the delegate.
If delegateSymbol Is Nothing OrElse Not sealedCandidateDiagnostics.Skip(1).Any() Then
If isExtension Then
For Each iDiagnostic In sealedCandidateDiagnostics
diagnosticInfos.Add(ErrorFactory.ErrorInfo(ERRID.ERR_ExtensionMethodOverloadCandidate3,
symbol, symbol.ContainingType, DirectCast(iDiagnostic, DiagnosticWithInfo).Info))
Next
Next
Else
For Each iDiagnostic In sealedCandidateDiagnostics
Dim msg = VisualBasicDiagnosticFormatter.Instance.Format(iDiagnostic.WithLocation(Location.None))
diagnosticInfos.Add(ErrorFactory.ErrorInfo(ERRID.ERR_OverloadCandidate2, symbol, DirectCast(iDiagnostic, DiagnosticWithInfo).Info))
Next
End If
Else
For Each iDiagnostic In sealedCandidateDiagnostics
Dim msg = VisualBasicDiagnosticFormatter.Instance.Format(iDiagnostic.WithLocation(Location.None))
diagnosticInfos.Add(ErrorFactory.ErrorInfo(ERRID.ERR_OverloadCandidate2, symbol, DirectCast(iDiagnostic, DiagnosticWithInfo).Info))
Next
End If
Else
If isExtension Then
diagnosticInfos.Add(ErrorFactory.ErrorInfo(ERRID.ERR_ExtensionMethodOverloadCandidate3,
If isExtension Then
diagnosticInfos.Add(ErrorFactory.ErrorInfo(ERRID.ERR_ExtensionMethodOverloadCandidate3,
symbol, symbol.ContainingType,
ErrorFactory.ErrorInfo(ERRID.ERR_DelegateBindingMismatch, symbol)))
Else
diagnosticInfos.Add(ErrorFactory.ErrorInfo(ERRID.ERR_OverloadCandidate2,
Else
diagnosticInfos.Add(ErrorFactory.ErrorInfo(ERRID.ERR_OverloadCandidate2,
symbol,
ErrorFactory.ErrorInfo(ERRID.ERR_DelegateBindingMismatch, symbol)))
End If
End If
End If
Next
Next
Dim diagnosticCoumpoundInfos() As DiagnosticInfo = diagnosticInfos.ToArrayAndFree()
If delegateSymbol Is Nothing Then
ReportDiagnostic(diagnostics, diagnosticLocation,
Dim diagnosticCoumpoundInfos() As DiagnosticInfo = diagnosticInfos.ToArrayAndFree()
If delegateSymbol Is Nothing Then
ReportDiagnostic(diagnostics, diagnosticLocation,
ErrorFactory.ErrorInfo(errorNo, CustomSymbolDisplayFormatter.ShortErrorName(candidates(0).Candidate.UnderlyingSymbol),
New CompoundDiagnosticInfo(diagnosticCoumpoundInfos)))
Else
ReportDiagnostic(diagnostics, diagnosticLocation,
Else
ReportDiagnostic(diagnostics, diagnosticLocation,
ErrorFactory.ErrorInfo(errorNo, CustomSymbolDisplayFormatter.ShortErrorName(candidates(0).Candidate.UnderlyingSymbol),
CustomSymbolDisplayFormatter.DelegateSignature(delegateSymbol),
New CompoundDiagnosticInfo(diagnosticCoumpoundInfos)))
End If
End If
diagnosticPerSymbol.Free()
End Sub
Private Shared Function ReportCommonErrorsFromLambdas(
diagnosticPerSymbol As ArrayBuilder(Of KeyValuePair(Of Symbol, ImmutableArray(Of Diagnostic))),
arguments As ImmutableArray(Of BoundExpression),
diagnostics As DiagnosticBag
) As Boolean
Dim haveCommonErrors As Boolean = False
For Each diagnostic In diagnosticPerSymbol(0).Value
If diagnostic.Severity <> DiagnosticSeverity.Error Then
Continue For
End If
For Each argument In arguments
If argument.Syntax.SyntaxTree Is diagnostic.Location.SourceTree AndAlso
argument.Kind = BoundKind.UnboundLambda Then
If argument.Syntax.Span.Contains(diagnostic.Location.SourceSpan) Then
Dim common As Boolean = True
For i As Integer = 1 To diagnosticPerSymbol.Count - 1
If Not diagnosticPerSymbol(i).Value.Contains(diagnostic) Then
common = False
Exit For
End If
Next
If common Then
haveCommonErrors = True
diagnostics.Add(diagnostic)
End If
Exit For
End If
End If
Next
Next
Return haveCommonErrors
End Function
''' <summary>
''' Should be kept in sync with OverloadResolution.MatchArguments. Anything that
......
......@@ -5909,11 +5909,9 @@ End Class
</compilation>, {SystemCoreRef})
CompilationUtils.AssertTheseDiagnostics(compilation,
<expected>
BC30518: Overload resolution failed because no accessible 'Where' can be called with these arguments:
Extension method 'Public Function Where(predicate As Func(Of Integer, Boolean)) As IEnumerable(Of Integer)' defined in 'Enumerable': 'Exit Try' can only appear inside a 'Try' statement.
Extension method 'Public Function Where(predicate As Func(Of Integer, Integer, Boolean)) As IEnumerable(Of Integer)' defined in 'Enumerable': 'Exit Try' can only appear inside a 'Try' statement.
x.Where(Function(y)
~~~~~
BC30393: 'Exit Try' can only appear inside a 'Try' statement.
Exit Try
~~~~~~~~
</expected>)
End Sub
......@@ -8178,11 +8176,9 @@ End Class
</compilation>, {SystemCoreRef})
CompilationUtils.AssertTheseDiagnostics(compilation,
<expected>
BC30518: Overload resolution failed because no accessible 'Where' can be called with these arguments:
Extension method 'Public Function Where(predicate As Func(Of Integer, Boolean)) As IEnumerable(Of Integer)' defined in 'Enumerable': Branching out of a 'Finally' is not valid.
Extension method 'Public Function Where(predicate As Func(Of Integer, Integer, Boolean)) As IEnumerable(Of Integer)' defined in 'Enumerable': Branching out of a 'Finally' is not valid.
x.Where(Function(y)
~~~~~
BC30101: Branching out of a 'Finally' is not valid.
Exit Function
~~~~~~~~~~~~~
BC42353: Function '&lt;anonymous method>' doesn't return a value on all code paths. Are you missing a 'Return' statement?
End Function)
~~~~~~~~~~~~
......
......@@ -44,11 +44,9 @@ End Class
AssertTheseDiagnostics(compilation,
<expected>
BC30518: Overload resolution failed because no accessible 'Where' can be called with these arguments:
Extension method 'Public Function Where(predicate As Func(Of Integer, Boolean)) As IEnumerable(Of Integer)' defined in 'Enumerable': Branching out of a 'Finally' is not valid.
Extension method 'Public Function Where(predicate As Func(Of Integer, Integer, Boolean)) As IEnumerable(Of Integer)' defined in 'Enumerable': Branching out of a 'Finally' is not valid.
lists.Where(Function(ByVal item)
~~~~~
BC30101: Branching out of a 'Finally' is not valid.
GoTo lab1
~~~~
</expected>)
End Sub
......
......@@ -5475,5 +5475,58 @@ BC30661: Field or property 'p1' is not found.
]]></expected>)
End Sub
<Fact, WorkItem(2604, "https://github.com/dotnet/roslyn/issues/2604")>
Public Sub FailureDueToAnErrorInALambda()
Dim compilationDef =
<compilation>
<file name="a.vb"><![CDATA[
Module Module1
Sub Main()
M0(0, Function() doesntexist)
M1(0, Function() doesntexist)
M2(0, Function() doesntexist)
End Sub
Sub M0(x As Integer, y As System.Func(Of Integer))
End Sub
Sub M1(x As Integer, y As System.Func(Of Integer))
End Sub
Sub M1(x As Long, y As System.Func(Of Long))
End Sub
Sub M2(x As Integer, y As System.Func(Of Integer))
End Sub
Sub M2(x As c1, y As System.Func(Of Long))
End Sub
End Module
Class c1
End Class
]]>
</file>
</compilation>
Dim compilation = CompilationUtils.CreateCompilationWithMscorlibAndVBRuntime(compilationDef, TestOptions.ReleaseExe)
CompilationUtils.AssertTheseDiagnostics(compilation,
<expected><![CDATA[
BC30451: 'doesntexist' is not declared. It may be inaccessible due to its protection level.
M0(0, Function() doesntexist)
~~~~~~~~~~~
BC30451: 'doesntexist' is not declared. It may be inaccessible due to its protection level.
M1(0, Function() doesntexist)
~~~~~~~~~~~
BC30451: 'doesntexist' is not declared. It may be inaccessible due to its protection level.
M2(0, Function() doesntexist)
~~~~~~~~~~~
]]></expected>)
End Sub
End Class
End Namespace
......@@ -1826,13 +1826,9 @@ BC42021: Cannot infer a return type because more than one type is possible; 'Obj
AssertTheseDiagnostics(compilation,
<expected>
BC30518: Overload resolution failed because no accessible '[Select]' can be called with these arguments:
Extension method 'Public Function [Select](Of TResult)(selector As Func(Of SnapshotSpan, TResult)) As IEnumerable(Of TResult)' defined in 'Enumerable': Cannot infer a return type because more than one type is possible. Consider adding an 'As' clause to specify the return type.
Extension method 'Public Function [Select](Of TResult)(selector As Func(Of SnapshotSpan, TResult)) As IEnumerable(Of TResult)' defined in 'Enumerable': Data type(s) of the type parameter(s) cannot be inferred from these arguments. Specifying the data type(s) explicitly might correct this error.
Extension method 'Public Function [Select](Of TResult)(selector As Func(Of SnapshotSpan, Integer, TResult)) As IEnumerable(Of TResult)' defined in 'Enumerable': Cannot infer a return type because more than one type is possible. Consider adding an 'As' clause to specify the return type.
Extension method 'Public Function [Select](Of TResult)(selector As Func(Of SnapshotSpan, Integer, TResult)) As IEnumerable(Of TResult)' defined in 'Enumerable': Data type(s) of the type parameter(s) cannot be inferred from these arguments. Specifying the data type(s) explicitly might correct this error.
BC36734: Cannot infer a return type because more than one type is possible. Consider adding an 'As' clause to specify the return type.
Dim replacementSpans = sourceSpans.Select(Function(ss)
~~~~~~
~~~~~~~~~~~~
</expected>)
End Sub
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册