Skip to content

Commit 3dae253

Browse files
Merge pull request #6278 from Microsoft/theyreNotTHATSpecial
Remove most special treatment of specialized signatures.
2 parents 7259074 + ad9bff8 commit 3dae253

File tree

92 files changed

+2826
-815
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+2826
-815
lines changed

src/compiler/checker.ts

Lines changed: 20 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -5905,29 +5905,24 @@ namespace ts {
59055905
const saveErrorInfo = errorInfo;
59065906

59075907
outer: for (const t of targetSignatures) {
5908-
if (!t.hasStringLiterals || target.flags & TypeFlags.FromSignature) {
5909-
// Only elaborate errors from the first failure
5910-
let shouldElaborateErrors = reportErrors;
5911-
for (const s of sourceSignatures) {
5912-
if (!s.hasStringLiterals || source.flags & TypeFlags.FromSignature) {
5913-
const related = signatureRelatedTo(s, t, shouldElaborateErrors);
5914-
if (related) {
5915-
result &= related;
5916-
errorInfo = saveErrorInfo;
5917-
continue outer;
5918-
}
5919-
shouldElaborateErrors = false;
5920-
}
5921-
}
5922-
// don't elaborate the primitive apparent types (like Number)
5923-
// because the actual primitives will have already been reported.
5924-
if (shouldElaborateErrors) {
5925-
reportError(Diagnostics.Type_0_provides_no_match_for_the_signature_1,
5926-
typeToString(source),
5927-
signatureToString(t, /*enclosingDeclaration*/ undefined, /*flags*/ undefined, kind));
5908+
// Only elaborate errors from the first failure
5909+
let shouldElaborateErrors = reportErrors;
5910+
for (const s of sourceSignatures) {
5911+
const related = signatureRelatedTo(s, t, shouldElaborateErrors);
5912+
if (related) {
5913+
result &= related;
5914+
errorInfo = saveErrorInfo;
5915+
continue outer;
59285916
}
5929-
return Ternary.False;
5917+
shouldElaborateErrors = false;
5918+
}
5919+
5920+
if (shouldElaborateErrors) {
5921+
reportError(Diagnostics.Type_0_provides_no_match_for_the_signature_1,
5922+
typeToString(source),
5923+
signatureToString(t, /*enclosingDeclaration*/ undefined, /*flags*/ undefined, kind));
59305924
}
5925+
return Ternary.False;
59315926
}
59325927
return result;
59335928
}
@@ -11702,8 +11697,6 @@ namespace ts {
1170211697
}
1170311698
}
1170411699
}
11705-
11706-
checkSpecializedSignatureDeclaration(node);
1170711700
}
1170811701

1170911702
function checkTypeForDuplicateIndexSignatures(node: Node) {
@@ -12014,48 +12007,6 @@ namespace ts {
1201412007
return (node.flags & NodeFlags.Private) && isInAmbientContext(node);
1201512008
}
1201612009

12017-
function checkSpecializedSignatureDeclaration(signatureDeclarationNode: SignatureDeclaration): void {
12018-
if (!produceDiagnostics) {
12019-
return;
12020-
}
12021-
const signature = getSignatureFromDeclaration(signatureDeclarationNode);
12022-
if (!signature.hasStringLiterals) {
12023-
return;
12024-
}
12025-
12026-
// TypeScript 1.0 spec (April 2014): 3.7.2.2
12027-
// Specialized signatures are not permitted in conjunction with a function body
12028-
if (nodeIsPresent((<FunctionLikeDeclaration>signatureDeclarationNode).body)) {
12029-
error(signatureDeclarationNode, Diagnostics.A_signature_with_an_implementation_cannot_use_a_string_literal_type);
12030-
return;
12031-
}
12032-
12033-
// TypeScript 1.0 spec (April 2014): 3.7.2.4
12034-
// Every specialized call or construct signature in an object type must be assignable
12035-
// to at least one non-specialized call or construct signature in the same object type
12036-
let signaturesToCheck: Signature[];
12037-
// Unnamed (call\construct) signatures in interfaces are inherited and not shadowed so examining just node symbol won't give complete answer.
12038-
// Use declaring type to obtain full list of signatures.
12039-
if (!signatureDeclarationNode.name && signatureDeclarationNode.parent && signatureDeclarationNode.parent.kind === SyntaxKind.InterfaceDeclaration) {
12040-
Debug.assert(signatureDeclarationNode.kind === SyntaxKind.CallSignature || signatureDeclarationNode.kind === SyntaxKind.ConstructSignature);
12041-
const signatureKind = signatureDeclarationNode.kind === SyntaxKind.CallSignature ? SignatureKind.Call : SignatureKind.Construct;
12042-
const containingSymbol = getSymbolOfNode(signatureDeclarationNode.parent);
12043-
const containingType = getDeclaredTypeOfSymbol(containingSymbol);
12044-
signaturesToCheck = getSignaturesOfType(containingType, signatureKind);
12045-
}
12046-
else {
12047-
signaturesToCheck = getSignaturesOfSymbol(getSymbolOfNode(signatureDeclarationNode));
12048-
}
12049-
12050-
for (const otherSignature of signaturesToCheck) {
12051-
if (!otherSignature.hasStringLiterals && isSignatureAssignableTo(signature, otherSignature, /*ignoreReturnTypes*/ false)) {
12052-
return;
12053-
}
12054-
}
12055-
12056-
error(signatureDeclarationNode, Diagnostics.Specialized_overload_signature_is_not_assignable_to_any_non_specialized_signature);
12057-
}
12058-
1205912010
function getEffectiveDeclarationFlags(n: Node, flagsToCheck: NodeFlags): NodeFlags {
1206012011
let flags = getCombinedNodeFlags(n);
1206112012

@@ -12277,28 +12228,10 @@ namespace ts {
1227712228
if (bodyDeclaration) {
1227812229
const signatures = getSignaturesOfSymbol(symbol);
1227912230
const bodySignature = getSignatureFromDeclaration(bodyDeclaration);
12280-
// If the implementation signature has string literals, we will have reported an error in
12281-
// checkSpecializedSignatureDeclaration
12282-
if (!bodySignature.hasStringLiterals) {
12283-
// TypeScript 1.0 spec (April 2014): 6.1
12284-
// If a function declaration includes overloads, the overloads determine the call
12285-
// signatures of the type given to the function object
12286-
// and the function implementation signature must be assignable to that type
12287-
//
12288-
// TypeScript 1.0 spec (April 2014): 3.8.4
12289-
// Note that specialized call and construct signatures (section 3.7.2.4) are not significant when determining assignment compatibility
12290-
// Consider checking against specialized signatures too. Not doing so creates a type hole:
12291-
//
12292-
// function g(x: "hi", y: boolean);
12293-
// function g(x: string, y: {});
12294-
// function g(x: string, y: string) { }
12295-
//
12296-
// The implementation is completely unrelated to the specialized signature, yet we do not check this.
12297-
for (const signature of signatures) {
12298-
if (!signature.hasStringLiterals && !isImplementationCompatibleWithOverload(bodySignature, signature)) {
12299-
error(signature.declaration, Diagnostics.Overload_signature_is_not_compatible_with_function_implementation);
12300-
break;
12301-
}
12231+
for (const signature of signatures) {
12232+
if (!isImplementationCompatibleWithOverload(bodySignature, signature)) {
12233+
error(signature.declaration, Diagnostics.Overload_signature_is_not_compatible_with_function_implementation);
12234+
break;
1230212235
}
1230312236
}
1230412237
}

tests/baselines/reference/ambientErrors.errors.txt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
tests/cases/conformance/ambient/ambientErrors.ts(2,15): error TS1039: Initializers are not allowed in ambient contexts.
2-
tests/cases/conformance/ambient/ambientErrors.ts(6,18): error TS2382: Specialized overload signature is not assignable to any non-specialized signature.
32
tests/cases/conformance/ambient/ambientErrors.ts(17,22): error TS2371: A parameter initializer is only allowed in a function or constructor implementation.
43
tests/cases/conformance/ambient/ambientErrors.ts(20,24): error TS1183: An implementation cannot be declared in ambient contexts.
54
tests/cases/conformance/ambient/ambientErrors.ts(29,9): error TS1066: In ambient enum declarations member initializer must be constant expression.
@@ -15,7 +14,7 @@ tests/cases/conformance/ambient/ambientErrors.ts(51,16): error TS2436: Ambient m
1514
tests/cases/conformance/ambient/ambientErrors.ts(57,5): error TS2309: An export assignment cannot be used in a module with other exported elements.
1615

1716

18-
==== tests/cases/conformance/ambient/ambientErrors.ts (15 errors) ====
17+
==== tests/cases/conformance/ambient/ambientErrors.ts (14 errors) ====
1918
// Ambient variable with an initializer
2019
declare var x = 4;
2120
~
@@ -24,8 +23,6 @@ tests/cases/conformance/ambient/ambientErrors.ts(57,5): error TS2309: An export
2423
// Ambient functions with invalid overloads
2524
declare function fn(x: number): string;
2625
declare function fn(x: 'foo'): number;
27-
~~
28-
!!! error TS2382: Specialized overload signature is not assignable to any non-specialized signature.
2926

3027
// Ambient functions with duplicate signatures
3128
declare function fn1(x: number): string;

tests/baselines/reference/callbackArgsDifferByOptionality.errors.txt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
tests/cases/compiler/callbackArgsDifferByOptionality.ts(1,23): error TS2382: Specialized overload signature is not assignable to any non-specialized signature.
21
tests/cases/compiler/callbackArgsDifferByOptionality.ts(4,5): error TS2304: Cannot find name 'cb'.
32

43

5-
==== tests/cases/compiler/callbackArgsDifferByOptionality.ts (2 errors) ====
4+
==== tests/cases/compiler/callbackArgsDifferByOptionality.ts (1 errors) ====
65
function x3(callback: (x?: 'hi') => number);
7-
~~~~~~~~~~~~~~~~~~~~
8-
!!! error TS2382: Specialized overload signature is not assignable to any non-specialized signature.
96
function x3(callback: (x: string) => number);
107
function x3(callback: (x: any) => number) {
118
cb();

tests/baselines/reference/constantOverloadFunctionNoSubtypeError.errors.txt

Lines changed: 0 additions & 26 deletions
This file was deleted.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
=== tests/cases/compiler/constantOverloadFunctionNoSubtypeError.ts ===
2+
class Base { foo() { } }
3+
>Base : Symbol(Base, Decl(constantOverloadFunctionNoSubtypeError.ts, 0, 0))
4+
>foo : Symbol(foo, Decl(constantOverloadFunctionNoSubtypeError.ts, 0, 12))
5+
6+
class Derived1 extends Base { bar() { } }
7+
>Derived1 : Symbol(Derived1, Decl(constantOverloadFunctionNoSubtypeError.ts, 0, 24))
8+
>Base : Symbol(Base, Decl(constantOverloadFunctionNoSubtypeError.ts, 0, 0))
9+
>bar : Symbol(bar, Decl(constantOverloadFunctionNoSubtypeError.ts, 1, 29))
10+
11+
class Derived2 extends Base { baz() { } }
12+
>Derived2 : Symbol(Derived2, Decl(constantOverloadFunctionNoSubtypeError.ts, 1, 41))
13+
>Base : Symbol(Base, Decl(constantOverloadFunctionNoSubtypeError.ts, 0, 0))
14+
>baz : Symbol(baz, Decl(constantOverloadFunctionNoSubtypeError.ts, 2, 29))
15+
16+
class Derived3 extends Base { biz() { } }
17+
>Derived3 : Symbol(Derived3, Decl(constantOverloadFunctionNoSubtypeError.ts, 2, 41))
18+
>Base : Symbol(Base, Decl(constantOverloadFunctionNoSubtypeError.ts, 0, 0))
19+
>biz : Symbol(biz, Decl(constantOverloadFunctionNoSubtypeError.ts, 3, 29))
20+
21+
function foo(tagName: 'canvas'): Derived3;
22+
>foo : Symbol(foo, Decl(constantOverloadFunctionNoSubtypeError.ts, 3, 41), Decl(constantOverloadFunctionNoSubtypeError.ts, 5, 42), Decl(constantOverloadFunctionNoSubtypeError.ts, 6, 40), Decl(constantOverloadFunctionNoSubtypeError.ts, 7, 40), Decl(constantOverloadFunctionNoSubtypeError.ts, 8, 36))
23+
>tagName : Symbol(tagName, Decl(constantOverloadFunctionNoSubtypeError.ts, 5, 13))
24+
>Derived3 : Symbol(Derived3, Decl(constantOverloadFunctionNoSubtypeError.ts, 2, 41))
25+
26+
function foo(tagName: 'div'): Derived2;
27+
>foo : Symbol(foo, Decl(constantOverloadFunctionNoSubtypeError.ts, 3, 41), Decl(constantOverloadFunctionNoSubtypeError.ts, 5, 42), Decl(constantOverloadFunctionNoSubtypeError.ts, 6, 40), Decl(constantOverloadFunctionNoSubtypeError.ts, 7, 40), Decl(constantOverloadFunctionNoSubtypeError.ts, 8, 36))
28+
>tagName : Symbol(tagName, Decl(constantOverloadFunctionNoSubtypeError.ts, 6, 13))
29+
>Derived2 : Symbol(Derived2, Decl(constantOverloadFunctionNoSubtypeError.ts, 1, 41))
30+
31+
function foo(tagName: 'span'): Derived1;
32+
>foo : Symbol(foo, Decl(constantOverloadFunctionNoSubtypeError.ts, 3, 41), Decl(constantOverloadFunctionNoSubtypeError.ts, 5, 42), Decl(constantOverloadFunctionNoSubtypeError.ts, 6, 40), Decl(constantOverloadFunctionNoSubtypeError.ts, 7, 40), Decl(constantOverloadFunctionNoSubtypeError.ts, 8, 36))
33+
>tagName : Symbol(tagName, Decl(constantOverloadFunctionNoSubtypeError.ts, 7, 13))
34+
>Derived1 : Symbol(Derived1, Decl(constantOverloadFunctionNoSubtypeError.ts, 0, 24))
35+
36+
function foo(tagName: number): Base;
37+
>foo : Symbol(foo, Decl(constantOverloadFunctionNoSubtypeError.ts, 3, 41), Decl(constantOverloadFunctionNoSubtypeError.ts, 5, 42), Decl(constantOverloadFunctionNoSubtypeError.ts, 6, 40), Decl(constantOverloadFunctionNoSubtypeError.ts, 7, 40), Decl(constantOverloadFunctionNoSubtypeError.ts, 8, 36))
38+
>tagName : Symbol(tagName, Decl(constantOverloadFunctionNoSubtypeError.ts, 8, 13))
39+
>Base : Symbol(Base, Decl(constantOverloadFunctionNoSubtypeError.ts, 0, 0))
40+
41+
function foo(tagName: any): Base {
42+
>foo : Symbol(foo, Decl(constantOverloadFunctionNoSubtypeError.ts, 3, 41), Decl(constantOverloadFunctionNoSubtypeError.ts, 5, 42), Decl(constantOverloadFunctionNoSubtypeError.ts, 6, 40), Decl(constantOverloadFunctionNoSubtypeError.ts, 7, 40), Decl(constantOverloadFunctionNoSubtypeError.ts, 8, 36))
43+
>tagName : Symbol(tagName, Decl(constantOverloadFunctionNoSubtypeError.ts, 9, 13))
44+
>Base : Symbol(Base, Decl(constantOverloadFunctionNoSubtypeError.ts, 0, 0))
45+
46+
return null;
47+
}
48+
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
=== tests/cases/compiler/constantOverloadFunctionNoSubtypeError.ts ===
2+
class Base { foo() { } }
3+
>Base : Base
4+
>foo : () => void
5+
6+
class Derived1 extends Base { bar() { } }
7+
>Derived1 : Derived1
8+
>Base : Base
9+
>bar : () => void
10+
11+
class Derived2 extends Base { baz() { } }
12+
>Derived2 : Derived2
13+
>Base : Base
14+
>baz : () => void
15+
16+
class Derived3 extends Base { biz() { } }
17+
>Derived3 : Derived3
18+
>Base : Base
19+
>biz : () => void
20+
21+
function foo(tagName: 'canvas'): Derived3;
22+
>foo : { (tagName: "canvas"): Derived3; (tagName: "div"): Derived2; (tagName: "span"): Derived1; (tagName: number): Base; }
23+
>tagName : "canvas"
24+
>Derived3 : Derived3
25+
26+
function foo(tagName: 'div'): Derived2;
27+
>foo : { (tagName: "canvas"): Derived3; (tagName: "div"): Derived2; (tagName: "span"): Derived1; (tagName: number): Base; }
28+
>tagName : "div"
29+
>Derived2 : Derived2
30+
31+
function foo(tagName: 'span'): Derived1;
32+
>foo : { (tagName: "canvas"): Derived3; (tagName: "div"): Derived2; (tagName: "span"): Derived1; (tagName: number): Base; }
33+
>tagName : "span"
34+
>Derived1 : Derived1
35+
36+
function foo(tagName: number): Base;
37+
>foo : { (tagName: "canvas"): Derived3; (tagName: "div"): Derived2; (tagName: "span"): Derived1; (tagName: number): Base; }
38+
>tagName : number
39+
>Base : Base
40+
41+
function foo(tagName: any): Base {
42+
>foo : { (tagName: "canvas"): Derived3; (tagName: "div"): Derived2; (tagName: "span"): Derived1; (tagName: number): Base; }
43+
>tagName : any
44+
>Base : Base
45+
46+
return null;
47+
>null : null
48+
}
49+

0 commit comments

Comments
 (0)