Skip to content

Add handling for 2-3 invalid overload candidates #1098

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
99 changes: 86 additions & 13 deletions internal/checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -8990,6 +8990,7 @@ func (c *Checker) isSignatureApplicable(node *ast.Node, args []*ast.Node, signat
}
}
}

if restType != nil {
spreadType := c.getSpreadArgumentType(args, argCount, len(args), restType, nil /*context*/, checkMode)
restArgCount := len(args) - argCount
Expand Down Expand Up @@ -9330,22 +9331,94 @@ func (c *Checker) tryGetRestTypeOfSignature(signature *Signature) *Type {
func (c *Checker) reportCallResolutionErrors(node *ast.Node, s *CallState, signatures []*Signature, headMessage *diagnostics.Message) {
switch {
case len(s.candidatesForArgumentError) != 0:
last := s.candidatesForArgumentError[len(s.candidatesForArgumentError)-1]
var diags []*ast.Diagnostic
c.isSignatureApplicable(s.node, s.args, last, c.assignableRelation, CheckModeNormal, true /*reportErrors*/, nil /*inferenceContext*/, &diags)
for _, diagnostic := range diags {
if len(s.candidatesForArgumentError) > 1 {
diagnostic = ast.NewDiagnosticChain(diagnostic, diagnostics.The_last_overload_gave_the_following_error)
diagnostic = ast.NewDiagnosticChain(diagnostic, diagnostics.No_overload_matches_this_call)
if len(s.candidatesForArgumentError) == 1 || len(s.candidatesForArgumentError) > 3 {
last := s.candidatesForArgumentError[len(s.candidatesForArgumentError)-1]
var diags []*ast.Diagnostic
c.isSignatureApplicable(s.node, s.args, last, c.assignableRelation, CheckModeNormal, true /*reportErrors*/, nil /*inferenceContext*/, &diags)
for _, diagnostic := range diags {
if len(s.candidatesForArgumentError) > 3 {
diagnostic = ast.NewDiagnosticChain(diagnostic, diagnostics.The_last_overload_gave_the_following_error)
diagnostic = ast.NewDiagnosticChain(diagnostic, diagnostics.No_overload_matches_this_call)
}
if headMessage != nil {
diagnostic = ast.NewDiagnosticChain(diagnostic, headMessage)
}
if last.declaration != nil && len(s.candidatesForArgumentError) > 3 {
diagnostic.AddRelatedInfo(NewDiagnosticForNode(last.declaration, diagnostics.The_last_overload_is_declared_here))
}
c.addImplementationSuccessElaboration(s, last, diagnostic)
c.diagnostics.Add(diagnostic)
}
if headMessage != nil {
diagnostic = ast.NewDiagnosticChain(diagnostic, headMessage)
} else {
// 2-3 candidates: show detailed errors for each individual overload
var allDiagnostics [][]*ast.Diagnostic
maxDiagCount := 0
minDiagCount := int(^uint(0) >> 1) // Max int value
minIndex := 0

for i, candidate := range s.candidatesForArgumentError {
var originalDiags []*ast.Diagnostic
c.isSignatureApplicable(s.node, s.args, candidate, c.assignableRelation, CheckModeNormal, true, nil, &originalDiags)

if len(originalDiags) > 0 {
chainedDiag := ast.NewDiagnosticChain(originalDiags[0], diagnostics.Overload_0_of_1_2_gave_the_following_error, i+1, len(s.candidates), c.signatureToString(candidate))
for j := 1; j < len(originalDiags); j++ {
chainedDiag.AddMessageChain(originalDiags[j])
}
diags := []*ast.Diagnostic{chainedDiag}

if len(originalDiags) <= minDiagCount {
minDiagCount = len(originalDiags)
minIndex = len(allDiagnostics)
}
maxDiagCount = max(maxDiagCount, len(originalDiags))
allDiagnostics = append(allDiagnostics, diags)
}
}
if last.declaration != nil && len(s.candidatesForArgumentError) > 1 {
diagnostic.AddRelatedInfo(NewDiagnosticForNode(last.declaration, diagnostics.The_last_overload_is_declared_here))

var diagsToShow []*ast.Diagnostic
if maxDiagCount > 1 {
diagsToShow = allDiagnostics[minIndex]
} else {
diagsToShow = core.Flatten(allDiagnostics)
}

if len(diagsToShow) > 0 {
var allRelatedInfo []*ast.Diagnostic
for _, diag := range diagsToShow {
allRelatedInfo = append(allRelatedInfo, diag.RelatedInformation()...)
}

mainDiag := ast.NewDiagnosticChain(diagsToShow[0], diagnostics.No_overload_matches_this_call)
for i := 1; i < len(diagsToShow); i++ {
mainDiag.AddMessageChain(diagsToShow[i])
}

if headMessage != nil {
mainDiag = ast.NewDiagnosticChain(mainDiag, headMessage)
}

allSameSpan := len(diagsToShow) > 0
if allSameSpan {
first := diagsToShow[0]
for i := 1; i < len(diagsToShow); i++ {
d := diagsToShow[i]
if d.File() != first.File() || d.Loc().Pos() != first.Loc().Pos() || d.Loc().Len() != first.Loc().Len() {
allSameSpan = false
break
}
}
}

if allSameSpan {
mainDiag.SetRelatedInfo(allRelatedInfo)
} else {
mainDiag = createDiagnosticForNodeFromMessageChain(ast.GetSourceFileOfNode(s.node), getErrorNodeForCallNode(s.node), mainDiag, allRelatedInfo)
}

c.addImplementationSuccessElaboration(s, s.candidatesForArgumentError[0], mainDiag)
c.diagnostics.Add(mainDiag)
}
c.addImplementationSuccessElaboration(s, last, diagnostic)
c.diagnostics.Add(diagnostic)
}
case s.candidateForArgumentArityError != nil:
c.diagnostics.Add(c.getArgumentArityError(s.node, []*Signature{s.candidateForArgumentArityError}, s.args, headMessage))
Expand Down
19 changes: 19 additions & 0 deletions internal/checker/utilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,25 @@ func NewDiagnosticChainForNode(chain *ast.Diagnostic, node *ast.Node, message *d
return NewDiagnosticForNode(node, message, args...)
}

func createDiagnosticForNodeFromMessageChain(sourceFile *ast.SourceFile, node *ast.Node, messageChain *ast.Diagnostic, relatedInformation []*ast.Diagnostic) *ast.Diagnostic {
if node == nil || messageChain == nil {
return messageChain
}

loc := binder.GetErrorRangeForNode(sourceFile, node)

diagnostic := &ast.Diagnostic{}
*diagnostic = *messageChain
diagnostic.SetFile(sourceFile)
diagnostic.SetLocation(loc)

if relatedInformation != nil {
diagnostic.SetRelatedInfo(relatedInformation)
}

return diagnostic
}

func findInMap[K comparable, V any](m map[K]V, predicate func(V) bool) V {
for _, value := range m {
if predicate(value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ constructorOverloads1.ts(3,5): error TS2392: Multiple constructor implementation
constructorOverloads1.ts(4,5): error TS2392: Multiple constructor implementations are not allowed.
constructorOverloads1.ts(7,5): error TS2392: Multiple constructor implementations are not allowed.
constructorOverloads1.ts(16,18): error TS2769: No overload matches this call.
The last overload gave the following error.
Overload 1 of 2, 'new (s: string): Foo', gave the following error.
Argument of type 'Foo' is not assignable to parameter of type 'string'.
Overload 2 of 2, 'new (n: number): Foo', gave the following error.
Argument of type 'Foo' is not assignable to parameter of type 'number'.
constructorOverloads1.ts(17,18): error TS2769: No overload matches this call.
The last overload gave the following error.
Overload 1 of 2, 'new (s: string): Foo', gave the following error.
Argument of type 'Foo[]' is not assignable to parameter of type 'string'.
Overload 2 of 2, 'new (n: number): Foo', gave the following error.
Argument of type 'Foo[]' is not assignable to parameter of type 'number'.


Expand Down Expand Up @@ -37,16 +41,18 @@ constructorOverloads1.ts(17,18): error TS2769: No overload matches this call.
var f3 = new Foo(f1);
~~
!!! error TS2769: No overload matches this call.
!!! error TS2769: The last overload gave the following error.
!!! error TS2769: Overload 1 of 2, 'new (s: string): Foo', gave the following error.
!!! error TS2769: Argument of type 'Foo' is not assignable to parameter of type 'string'.
!!! error TS2769: Overload 2 of 2, 'new (n: number): Foo', gave the following error.
!!! error TS2769: Argument of type 'Foo' is not assignable to parameter of type 'number'.
!!! related TS2771 constructorOverloads1.ts:3:5: The last overload is declared here.
!!! related TS2793 constructorOverloads1.ts:4:5: The call would have succeeded against this implementation, but implementation signatures of overloads are not externally visible.
var f4 = new Foo([f1,f2,f3]);
~~~~~~~~~~
!!! error TS2769: No overload matches this call.
!!! error TS2769: The last overload gave the following error.
!!! error TS2769: Overload 1 of 2, 'new (s: string): Foo', gave the following error.
!!! error TS2769: Argument of type 'Foo[]' is not assignable to parameter of type 'string'.
!!! error TS2769: Overload 2 of 2, 'new (n: number): Foo', gave the following error.
!!! error TS2769: Argument of type 'Foo[]' is not assignable to parameter of type 'number'.
!!! related TS2771 constructorOverloads1.ts:3:5: The last overload is declared here.
!!! related TS2793 constructorOverloads1.ts:4:5: The call would have succeeded against this implementation, but implementation signatures of overloads are not externally visible.

f1.bar1();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,39 @@
constructorOverloads1.ts(7,5): error TS2392: Multiple constructor implementations are not allowed.
constructorOverloads1.ts(16,18): error TS2769: No overload matches this call.
- Overload 1 of 2, '(s: string): Foo', gave the following error.
- Argument of type 'Foo' is not assignable to parameter of type 'string'.
+ Overload 1 of 2, 'new (s: string): Foo', gave the following error.
Argument of type 'Foo' is not assignable to parameter of type 'string'.
- Overload 2 of 2, '(n: number): Foo', gave the following error.
+ The last overload gave the following error.
+ Overload 2 of 2, 'new (n: number): Foo', gave the following error.
Argument of type 'Foo' is not assignable to parameter of type 'number'.
constructorOverloads1.ts(17,18): error TS2769: No overload matches this call.
- Overload 1 of 2, '(s: string): Foo', gave the following error.
- Argument of type 'Foo[]' is not assignable to parameter of type 'string'.
+ Overload 1 of 2, 'new (s: string): Foo', gave the following error.
Argument of type 'Foo[]' is not assignable to parameter of type 'string'.
- Overload 2 of 2, '(n: number): Foo', gave the following error.
+ The last overload gave the following error.
+ Overload 2 of 2, 'new (n: number): Foo', gave the following error.
Argument of type 'Foo[]' is not assignable to parameter of type 'number'.


@@= skipped -38, +34 lines =@@
@@= skipped -38, +38 lines =@@
var f3 = new Foo(f1);
~~
!!! error TS2769: No overload matches this call.
-!!! error TS2769: Overload 1 of 2, '(s: string): Foo', gave the following error.
-!!! error TS2769: Argument of type 'Foo' is not assignable to parameter of type 'string'.
+!!! error TS2769: Overload 1 of 2, 'new (s: string): Foo', gave the following error.
!!! error TS2769: Argument of type 'Foo' is not assignable to parameter of type 'string'.
-!!! error TS2769: Overload 2 of 2, '(n: number): Foo', gave the following error.
+!!! error TS2769: The last overload gave the following error.
+!!! error TS2769: Overload 2 of 2, 'new (n: number): Foo', gave the following error.
!!! error TS2769: Argument of type 'Foo' is not assignable to parameter of type 'number'.
+!!! related TS2771 constructorOverloads1.ts:3:5: The last overload is declared here.
!!! related TS2793 constructorOverloads1.ts:4:5: The call would have succeeded against this implementation, but implementation signatures of overloads are not externally visible.
var f4 = new Foo([f1,f2,f3]);
~~~~~~~~~~
!!! error TS2769: No overload matches this call.
-!!! error TS2769: Overload 1 of 2, '(s: string): Foo', gave the following error.
-!!! error TS2769: Argument of type 'Foo[]' is not assignable to parameter of type 'string'.
+!!! error TS2769: Overload 1 of 2, 'new (s: string): Foo', gave the following error.
!!! error TS2769: Argument of type 'Foo[]' is not assignable to parameter of type 'string'.
-!!! error TS2769: Overload 2 of 2, '(n: number): Foo', gave the following error.
+!!! error TS2769: The last overload gave the following error.
+!!! error TS2769: Overload 2 of 2, 'new (n: number): Foo', gave the following error.
!!! error TS2769: Argument of type 'Foo[]' is not assignable to parameter of type 'number'.
+!!! related TS2771 constructorOverloads1.ts:3:5: The last overload is declared here.
!!! related TS2793 constructorOverloads1.ts:4:5: The call would have succeeded against this implementation, but implementation signatures of overloads are not externally visible.

f1.bar1();

Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
destructuringTuple.ts(11,7): error TS2461: Type 'number' is not an array type.
destructuringTuple.ts(11,48): error TS2769: No overload matches this call.
The last overload gave the following error.
Overload 1 of 3, '(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: number[]) => number, initialValue: number): number', gave the following error.
Type 'never[]' is not assignable to type 'number'.
Overload 2 of 3, '(callbackfn: (previousValue: [], currentValue: number, currentIndex: number, array: number[]) => [], initialValue: []): []', gave the following error.
Type 'never[]' is not assignable to type '[]'.
Target allows only 0 element(s) but source may have more.
destructuringTuple.ts(11,60): error TS2769: No overload matches this call.
The last overload gave the following error.
Overload 1 of 2, '(...items: ConcatArray<never>[]): never[]', gave the following error.
Argument of type 'number' is not assignable to parameter of type 'ConcatArray<never>'.
Overload 2 of 2, '(...items: ConcatArray<never>[]): never[]', gave the following error.
Argument of type 'number' is not assignable to parameter of type 'ConcatArray<never>'.


Expand All @@ -24,16 +28,19 @@ destructuringTuple.ts(11,60): error TS2769: No overload matches this call.
!!! error TS2461: Type 'number' is not an array type.
~~~~~~~~~~~~~~~
!!! error TS2769: No overload matches this call.
!!! error TS2769: The last overload gave the following error.
!!! error TS2769: Overload 1 of 3, '(callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: number[]) => number, initialValue: number): number', gave the following error.
!!! error TS2769: Type 'never[]' is not assignable to type 'number'.
!!! error TS2769: Overload 2 of 3, '(callbackfn: (previousValue: [], currentValue: number, currentIndex: number, array: number[]) => [], initialValue: []): []', gave the following error.
!!! error TS2769: Type 'never[]' is not assignable to type '[]'.
!!! error TS2769: Target allows only 0 element(s) but source may have more.
!!! related TS6502 lib.es5.d.ts:--:--: The expected type comes from the return type of this signature.
!!! related TS2771 lib.es5.d.ts:--:--: The last overload is declared here.
!!! related TS6502 lib.es5.d.ts:--:--: The expected type comes from the return type of this signature.
~~
!!! error TS2769: No overload matches this call.
!!! error TS2769: The last overload gave the following error.
!!! error TS2769: Overload 1 of 2, '(...items: ConcatArray<never>[]): never[]', gave the following error.
!!! error TS2769: Argument of type 'number' is not assignable to parameter of type 'ConcatArray<never>'.
!!! error TS2769: Overload 2 of 2, '(...items: ConcatArray<never>[]): never[]', gave the following error.
!!! error TS2769: Argument of type 'number' is not assignable to parameter of type 'ConcatArray<never>'.
!!! related TS2771 lib.es5.d.ts:--:--: The last overload is declared here.

const [oops2] = [1, 2, 3].reduce((acc: number[], e) => acc.concat(e), []);

This file was deleted.

Loading