Skip to content

Commit a4770af

Browse files
committed
Merge pull request microsoft#5777 from Microsoft/elaborate-interface-signature-errors
Elaborate interface signature errors
2 parents f7303cd + 4338dcb commit a4770af

28 files changed

Lines changed: 166 additions & 26 deletions

src/compiler/checker.ts

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,14 @@ namespace ts {
379379
return node.kind === SyntaxKind.SourceFile && !isExternalOrCommonJsModule(<SourceFile>node);
380380
}
381381

382+
/** Is this type one of the apparent types created from the primitive types. */
383+
function isPrimitiveApparentType(type: Type): boolean {
384+
return type === globalStringType ||
385+
type === globalNumberType ||
386+
type === globalBooleanType ||
387+
type === globalESSymbolType;
388+
}
389+
382390
function getSymbol(symbols: SymbolTable, name: string, meaning: SymbolFlags): Symbol {
383391
if (meaning && hasProperty(symbols, name)) {
384392
const symbol = symbols[name];
@@ -1521,9 +1529,9 @@ namespace ts {
15211529
return result;
15221530
}
15231531

1524-
function signatureToString(signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string {
1532+
function signatureToString(signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind): string {
15251533
const writer = getSingleLineStringWriter();
1526-
getSymbolDisplayBuilder().buildSignatureDisplay(signature, writer, enclosingDeclaration, flags);
1534+
getSymbolDisplayBuilder().buildSignatureDisplay(signature, writer, enclosingDeclaration, flags, kind);
15271535
const result = writer.string();
15281536
releaseStringWriter(writer);
15291537

@@ -1875,7 +1883,7 @@ namespace ts {
18751883
if (flags & TypeFormatFlags.InElementType) {
18761884
writePunctuation(writer, SyntaxKind.OpenParenToken);
18771885
}
1878-
buildSignatureDisplay(resolved.callSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, symbolStack);
1886+
buildSignatureDisplay(resolved.callSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, /*kind*/ undefined, symbolStack);
18791887
if (flags & TypeFormatFlags.InElementType) {
18801888
writePunctuation(writer, SyntaxKind.CloseParenToken);
18811889
}
@@ -1887,7 +1895,7 @@ namespace ts {
18871895
}
18881896
writeKeyword(writer, SyntaxKind.NewKeyword);
18891897
writeSpace(writer);
1890-
buildSignatureDisplay(resolved.constructSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, symbolStack);
1898+
buildSignatureDisplay(resolved.constructSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, /*kind*/ undefined, symbolStack);
18911899
if (flags & TypeFormatFlags.InElementType) {
18921900
writePunctuation(writer, SyntaxKind.CloseParenToken);
18931901
}
@@ -1901,15 +1909,12 @@ namespace ts {
19011909
writer.writeLine();
19021910
writer.increaseIndent();
19031911
for (const signature of resolved.callSignatures) {
1904-
buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, symbolStack);
1912+
buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, /*kind*/ undefined, symbolStack);
19051913
writePunctuation(writer, SyntaxKind.SemicolonToken);
19061914
writer.writeLine();
19071915
}
19081916
for (const signature of resolved.constructSignatures) {
1909-
writeKeyword(writer, SyntaxKind.NewKeyword);
1910-
writeSpace(writer);
1911-
1912-
buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, symbolStack);
1917+
buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, SignatureKind.Construct, symbolStack);
19131918
writePunctuation(writer, SyntaxKind.SemicolonToken);
19141919
writer.writeLine();
19151920
}
@@ -1950,7 +1955,7 @@ namespace ts {
19501955
if (p.flags & SymbolFlags.Optional) {
19511956
writePunctuation(writer, SyntaxKind.QuestionToken);
19521957
}
1953-
buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, symbolStack);
1958+
buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, /*kind*/ undefined, symbolStack);
19541959
writePunctuation(writer, SyntaxKind.SemicolonToken);
19551960
writer.writeLine();
19561961
}
@@ -2070,7 +2075,12 @@ namespace ts {
20702075
buildTypeDisplay(returnType, writer, enclosingDeclaration, flags, symbolStack);
20712076
}
20722077

2073-
function buildSignatureDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
2078+
function buildSignatureDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind, symbolStack?: Symbol[]) {
2079+
if (kind === SignatureKind.Construct) {
2080+
writeKeyword(writer, SyntaxKind.NewKeyword);
2081+
writeSpace(writer);
2082+
}
2083+
20742084
if (signature.target && (flags & TypeFormatFlags.WriteTypeArgumentsOfSignature)) {
20752085
// Instantiated signature, write type arguments instead
20762086
// This is achieved by passing in the mapper separately
@@ -5442,20 +5452,26 @@ namespace ts {
54425452

54435453
outer: for (const t of targetSignatures) {
54445454
if (!t.hasStringLiterals || target.flags & TypeFlags.FromSignature) {
5445-
let localErrors = reportErrors;
5446-
const checkedAbstractAssignability = false;
5455+
// Only elaborate errors from the first failure
5456+
let shouldElaborateErrors = reportErrors;
54475457
for (const s of sourceSignatures) {
54485458
if (!s.hasStringLiterals || source.flags & TypeFlags.FromSignature) {
5449-
const related = signatureRelatedTo(s, t, localErrors);
5459+
const related = signatureRelatedTo(s, t, shouldElaborateErrors);
54505460
if (related) {
54515461
result &= related;
54525462
errorInfo = saveErrorInfo;
54535463
continue outer;
54545464
}
5455-
// Only report errors from the first failure
5456-
localErrors = false;
5465+
shouldElaborateErrors = false;
54575466
}
54585467
}
5468+
// don't elaborate the primitive apparent types (like Number)
5469+
// because the actual primitives will have already been reported.
5470+
if (shouldElaborateErrors && !isPrimitiveApparentType(source)) {
5471+
reportError(Diagnostics.Type_0_provides_no_match_for_the_signature_1,
5472+
typeToString(source),
5473+
signatureToString(t, /*enclosingDeclaration*/ undefined, /*flags*/ undefined, kind));
5474+
}
54595475
return Ternary.False;
54605476
}
54615477
}

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1732,6 +1732,10 @@
17321732
"category": "Error",
17331733
"code": 2657
17341734
},
1735+
"Type '{0}' provides no match for the signature '{1}'": {
1736+
"category": "Error",
1737+
"code": 2658
1738+
},
17351739
"Import declaration '{0}' is using private name '{1}'.": {
17361740
"category": "Error",
17371741
"code": 4000

src/compiler/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1757,7 +1757,7 @@ namespace ts {
17571757
export interface SymbolDisplayBuilder {
17581758
buildTypeDisplay(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
17591759
buildSymbolDisplay(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags): void;
1760-
buildSignatureDisplay(signatures: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
1760+
buildSignatureDisplay(signatures: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind): void;
17611761
buildParameterDisplay(parameter: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
17621762
buildTypeParameterDisplay(tp: TypeParameter, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
17631763
buildTypeParameterDisplayFromSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaraiton?: Node, flags?: TypeFormatFlags): void;

tests/baselines/reference/assignmentCompatWithConstructSignatures.errors.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures.ts(28,1): error TS2322: Type 'S2' is not assignable to type 'T'.
2+
Type 'S2' provides no match for the signature 'new (x: number): void'
23
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures.ts(29,1): error TS2322: Type '(x: string) => void' is not assignable to type 'T'.
4+
Type '(x: string) => void' provides no match for the signature 'new (x: number): void'
35
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures.ts(30,1): error TS2322: Type '(x: string) => number' is not assignable to type 'T'.
6+
Type '(x: string) => number' provides no match for the signature 'new (x: number): void'
47
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures.ts(31,1): error TS2322: Type '(x: string) => string' is not assignable to type 'T'.
8+
Type '(x: string) => string' provides no match for the signature 'new (x: number): void'
59
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures.ts(32,1): error TS2322: Type 'S2' is not assignable to type 'new (x: number) => void'.
10+
Type 'S2' provides no match for the signature 'new (x: number): void'
611
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures.ts(33,1): error TS2322: Type '(x: string) => void' is not assignable to type 'new (x: number) => void'.
12+
Type '(x: string) => void' provides no match for the signature 'new (x: number): void'
713
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures.ts(34,1): error TS2322: Type '(x: string) => number' is not assignable to type 'new (x: number) => void'.
14+
Type '(x: string) => number' provides no match for the signature 'new (x: number): void'
815
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures.ts(35,1): error TS2322: Type '(x: string) => string' is not assignable to type 'new (x: number) => void'.
16+
Type '(x: string) => string' provides no match for the signature 'new (x: number): void'
917

1018

1119
==== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures.ts (8 errors) ====
@@ -39,25 +47,33 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
3947
t = s2;
4048
~
4149
!!! error TS2322: Type 'S2' is not assignable to type 'T'.
50+
!!! error TS2322: Type 'S2' provides no match for the signature 'new (x: number): void'
4251
t = a3;
4352
~
4453
!!! error TS2322: Type '(x: string) => void' is not assignable to type 'T'.
54+
!!! error TS2322: Type '(x: string) => void' provides no match for the signature 'new (x: number): void'
4555
t = (x: string) => 1;
4656
~
4757
!!! error TS2322: Type '(x: string) => number' is not assignable to type 'T'.
58+
!!! error TS2322: Type '(x: string) => number' provides no match for the signature 'new (x: number): void'
4859
t = function (x: string) { return ''; }
4960
~
5061
!!! error TS2322: Type '(x: string) => string' is not assignable to type 'T'.
62+
!!! error TS2322: Type '(x: string) => string' provides no match for the signature 'new (x: number): void'
5163
a = s2;
5264
~
5365
!!! error TS2322: Type 'S2' is not assignable to type 'new (x: number) => void'.
66+
!!! error TS2322: Type 'S2' provides no match for the signature 'new (x: number): void'
5467
a = a3;
5568
~
5669
!!! error TS2322: Type '(x: string) => void' is not assignable to type 'new (x: number) => void'.
70+
!!! error TS2322: Type '(x: string) => void' provides no match for the signature 'new (x: number): void'
5771
a = (x: string) => 1;
5872
~
5973
!!! error TS2322: Type '(x: string) => number' is not assignable to type 'new (x: number) => void'.
74+
!!! error TS2322: Type '(x: string) => number' provides no match for the signature 'new (x: number): void'
6075
a = function (x: string) { return ''; }
6176
~
6277
!!! error TS2322: Type '(x: string) => string' is not assignable to type 'new (x: number) => void'.
78+
!!! error TS2322: Type '(x: string) => string' provides no match for the signature 'new (x: number): void'
6379

tests/baselines/reference/assignmentCompatWithConstructSignatures2.errors.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,23 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
99
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures2.ts(34,1): error TS2322: Type 'S2' is not assignable to type 'T'.
1010
Types of property 'f' are incompatible.
1111
Type '(x: string) => void' is not assignable to type 'new (x: number) => void'.
12+
Type '(x: string) => void' provides no match for the signature 'new (x: number): void'
1213
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures2.ts(35,1): error TS2322: Type '{ f(x: string): void; }' is not assignable to type 'T'.
1314
Types of property 'f' are incompatible.
1415
Type '(x: string) => void' is not assignable to type 'new (x: number) => void'.
16+
Type '(x: string) => void' provides no match for the signature 'new (x: number): void'
1517
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures2.ts(36,1): error TS2322: Type '(x: string) => number' is not assignable to type 'T'.
1618
Property 'f' is missing in type '(x: string) => number'.
1719
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures2.ts(37,1): error TS2322: Type '(x: string) => string' is not assignable to type 'T'.
1820
Property 'f' is missing in type '(x: string) => string'.
1921
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures2.ts(38,1): error TS2322: Type 'S2' is not assignable to type '{ f: new (x: number) => void; }'.
2022
Types of property 'f' are incompatible.
2123
Type '(x: string) => void' is not assignable to type 'new (x: number) => void'.
24+
Type '(x: string) => void' provides no match for the signature 'new (x: number): void'
2225
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures2.ts(39,1): error TS2322: Type '{ f(x: string): void; }' is not assignable to type '{ f: new (x: number) => void; }'.
2326
Types of property 'f' are incompatible.
2427
Type '(x: string) => void' is not assignable to type 'new (x: number) => void'.
28+
Type '(x: string) => void' provides no match for the signature 'new (x: number): void'
2529
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures2.ts(40,1): error TS2322: Type '(x: string) => number' is not assignable to type '{ f: new (x: number) => void; }'.
2630
Property 'f' is missing in type '(x: string) => number'.
2731
tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithConstructSignatures2.ts(41,1): error TS2322: Type '(x: string) => string' is not assignable to type '{ f: new (x: number) => void; }'.
@@ -79,11 +83,13 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
7983
!!! error TS2322: Type 'S2' is not assignable to type 'T'.
8084
!!! error TS2322: Types of property 'f' are incompatible.
8185
!!! error TS2322: Type '(x: string) => void' is not assignable to type 'new (x: number) => void'.
86+
!!! error TS2322: Type '(x: string) => void' provides no match for the signature 'new (x: number): void'
8287
t = a3;
8388
~
8489
!!! error TS2322: Type '{ f(x: string): void; }' is not assignable to type 'T'.
8590
!!! error TS2322: Types of property 'f' are incompatible.
8691
!!! error TS2322: Type '(x: string) => void' is not assignable to type 'new (x: number) => void'.
92+
!!! error TS2322: Type '(x: string) => void' provides no match for the signature 'new (x: number): void'
8793
t = (x: string) => 1;
8894
~
8995
!!! error TS2322: Type '(x: string) => number' is not assignable to type 'T'.
@@ -97,11 +103,13 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme
97103
!!! error TS2322: Type 'S2' is not assignable to type '{ f: new (x: number) => void; }'.
98104
!!! error TS2322: Types of property 'f' are incompatible.
99105
!!! error TS2322: Type '(x: string) => void' is not assignable to type 'new (x: number) => void'.
106+
!!! error TS2322: Type '(x: string) => void' provides no match for the signature 'new (x: number): void'
100107
a = a3;
101108
~
102109
!!! error TS2322: Type '{ f(x: string): void; }' is not assignable to type '{ f: new (x: number) => void; }'.
103110
!!! error TS2322: Types of property 'f' are incompatible.
104111
!!! error TS2322: Type '(x: string) => void' is not assignable to type 'new (x: number) => void'.
112+
!!! error TS2322: Type '(x: string) => void' provides no match for the signature 'new (x: number): void'
105113
a = (x: string) => 1;
106114
~
107115
!!! error TS2322: Type '(x: string) => number' is not assignable to type '{ f: new (x: number) => void; }'.

0 commit comments

Comments
 (0)