Skip to content

Commit 4b534dc

Browse files
authored
Check overload tag against implementation (#52474)
1 parent 2976b6b commit 4b534dc

File tree

6 files changed

+429
-1
lines changed

6 files changed

+429
-1
lines changed

src/compiler/checker.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,7 @@ import {
748748
JSDocMemberName,
749749
JSDocNullableType,
750750
JSDocOptionalType,
751+
JSDocOverloadTag,
751752
JSDocParameterTag,
752753
JSDocPrivateTag,
753754
JSDocPropertyLikeTag,
@@ -38692,6 +38693,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3869238693
lastSeenNonAmbientDeclaration = node as FunctionLikeDeclaration;
3869338694
}
3869438695
}
38696+
if (isInJSFile(current) && isFunctionLike(current) && current.jsDoc) {
38697+
for (const node of current.jsDoc) {
38698+
if (node.tags) {
38699+
for (const tag of node.tags) {
38700+
if (isJSDocOverloadTag(tag)) {
38701+
hasOverloads = true;
38702+
}
38703+
}
38704+
}
38705+
}
38706+
}
3869538707
}
3869638708
}
3869738709

@@ -38743,8 +38755,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3874338755
const bodySignature = getSignatureFromDeclaration(bodyDeclaration);
3874438756
for (const signature of signatures) {
3874538757
if (!isImplementationCompatibleWithOverload(bodySignature, signature)) {
38758+
const errorNode = signature.declaration && isJSDocSignature(signature.declaration)
38759+
? (signature.declaration.parent as JSDocOverloadTag | JSDocCallbackTag).tagName
38760+
: signature.declaration;
3874638761
addRelatedInfo(
38747-
error(signature.declaration, Diagnostics.This_overload_signature_is_not_compatible_with_its_implementation_signature),
38762+
error(errorNode, Diagnostics.This_overload_signature_is_not_compatible_with_its_implementation_signature),
3874838763
createDiagnosticForNode(bodyDeclaration, Diagnostics.The_implementation_signature_is_declared_here)
3874938764
);
3875038765
break;
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
tests/cases/conformance/jsdoc/overloadTag1.js(7,5): error TS2394: This overload signature is not compatible with its implementation signature.
2+
tests/cases/conformance/jsdoc/overloadTag1.js(25,10): error TS2769: No overload matches this call.
3+
Overload 1 of 2, '(a: number, b: number): number', gave the following error.
4+
Argument of type 'string' is not assignable to parameter of type 'number'.
5+
Overload 2 of 2, '(a: string, b: boolean): string', gave the following error.
6+
Argument of type 'string' is not assignable to parameter of type 'boolean'.
7+
tests/cases/conformance/jsdoc/overloadTag1.js(43,1): error TS2769: No overload matches this call.
8+
Overload 1 of 2, '(a: number, b: number): number', gave the following error.
9+
Argument of type 'string' is not assignable to parameter of type 'number'.
10+
Overload 2 of 2, '(a: string, b: boolean): string', gave the following error.
11+
Argument of type 'string' is not assignable to parameter of type 'boolean'.
12+
13+
14+
==== tests/cases/conformance/jsdoc/overloadTag1.js (3 errors) ====
15+
/**
16+
* @overload
17+
* @param {number} a
18+
* @param {number} b
19+
* @returns {number}
20+
*
21+
* @overload
22+
~~~~~~~~
23+
!!! error TS2394: This overload signature is not compatible with its implementation signature.
24+
!!! related TS2750 tests/cases/conformance/jsdoc/overloadTag1.js:16:17: The implementation signature is declared here.
25+
* @param {string} a
26+
* @param {boolean} b
27+
* @returns {string}
28+
*
29+
* @param {string | number} a
30+
* @param {string | number} b
31+
* @returns {string | number}
32+
*/
33+
export function overloaded(a,b) {
34+
if (typeof a === "string" && typeof b === "string") {
35+
return a + b;
36+
} else if (typeof a === "number" && typeof b === "number") {
37+
return a + b;
38+
}
39+
throw new Error("Invalid arguments");
40+
}
41+
var o1 = overloaded(1,2)
42+
var o2 = overloaded("zero", "one")
43+
~~~~~~~~~~~~~~~~~~~~~~~~~
44+
!!! error TS2769: No overload matches this call.
45+
!!! error TS2769: Overload 1 of 2, '(a: number, b: number): number', gave the following error.
46+
!!! error TS2769: Argument of type 'string' is not assignable to parameter of type 'number'.
47+
!!! error TS2769: Overload 2 of 2, '(a: string, b: boolean): string', gave the following error.
48+
!!! error TS2769: Argument of type 'string' is not assignable to parameter of type 'boolean'.
49+
var o3 = overloaded("a",false)
50+
51+
/**
52+
* @overload
53+
* @param {number} a
54+
* @param {number} b
55+
* @returns {number}
56+
*
57+
* @overload
58+
* @param {string} a
59+
* @param {boolean} b
60+
* @returns {string}
61+
*/
62+
export function uncheckedInternally(a, b) {
63+
return a + b;
64+
}
65+
uncheckedInternally(1,2)
66+
uncheckedInternally("zero", "one")
67+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
68+
!!! error TS2769: No overload matches this call.
69+
!!! error TS2769: Overload 1 of 2, '(a: number, b: number): number', gave the following error.
70+
!!! error TS2769: Argument of type 'string' is not assignable to parameter of type 'number'.
71+
!!! error TS2769: Overload 2 of 2, '(a: string, b: boolean): string', gave the following error.
72+
!!! error TS2769: Argument of type 'string' is not assignable to parameter of type 'boolean'.
73+
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
//// [overloadTag1.js]
2+
/**
3+
* @overload
4+
* @param {number} a
5+
* @param {number} b
6+
* @returns {number}
7+
*
8+
* @overload
9+
* @param {string} a
10+
* @param {boolean} b
11+
* @returns {string}
12+
*
13+
* @param {string | number} a
14+
* @param {string | number} b
15+
* @returns {string | number}
16+
*/
17+
export function overloaded(a,b) {
18+
if (typeof a === "string" && typeof b === "string") {
19+
return a + b;
20+
} else if (typeof a === "number" && typeof b === "number") {
21+
return a + b;
22+
}
23+
throw new Error("Invalid arguments");
24+
}
25+
var o1 = overloaded(1,2)
26+
var o2 = overloaded("zero", "one")
27+
var o3 = overloaded("a",false)
28+
29+
/**
30+
* @overload
31+
* @param {number} a
32+
* @param {number} b
33+
* @returns {number}
34+
*
35+
* @overload
36+
* @param {string} a
37+
* @param {boolean} b
38+
* @returns {string}
39+
*/
40+
export function uncheckedInternally(a, b) {
41+
return a + b;
42+
}
43+
uncheckedInternally(1,2)
44+
uncheckedInternally("zero", "one")
45+
46+
47+
//// [overloadTag1.js]
48+
"use strict";
49+
Object.defineProperty(exports, "__esModule", { value: true });
50+
exports.uncheckedInternally = exports.overloaded = void 0;
51+
/**
52+
* @overload
53+
* @param {number} a
54+
* @param {number} b
55+
* @returns {number}
56+
*
57+
* @overload
58+
* @param {string} a
59+
* @param {boolean} b
60+
* @returns {string}
61+
*
62+
* @param {string | number} a
63+
* @param {string | number} b
64+
* @returns {string | number}
65+
*/
66+
function overloaded(a, b) {
67+
if (typeof a === "string" && typeof b === "string") {
68+
return a + b;
69+
}
70+
else if (typeof a === "number" && typeof b === "number") {
71+
return a + b;
72+
}
73+
throw new Error("Invalid arguments");
74+
}
75+
exports.overloaded = overloaded;
76+
var o1 = overloaded(1, 2);
77+
var o2 = overloaded("zero", "one");
78+
var o3 = overloaded("a", false);
79+
/**
80+
* @overload
81+
* @param {number} a
82+
* @param {number} b
83+
* @returns {number}
84+
*
85+
* @overload
86+
* @param {string} a
87+
* @param {boolean} b
88+
* @returns {string}
89+
*/
90+
function uncheckedInternally(a, b) {
91+
return a + b;
92+
}
93+
exports.uncheckedInternally = uncheckedInternally;
94+
uncheckedInternally(1, 2);
95+
uncheckedInternally("zero", "one");
96+
97+
98+
//// [overloadTag1.d.ts]
99+
export function overloaded(a: number, b: number): number;
100+
export function overloaded(a: string, b: boolean): string;
101+
export function uncheckedInternally(a: number, b: number): number;
102+
export function uncheckedInternally(a: string, b: boolean): string;
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
=== tests/cases/conformance/jsdoc/overloadTag1.js ===
2+
/**
3+
* @overload
4+
* @param {number} a
5+
* @param {number} b
6+
* @returns {number}
7+
*
8+
* @overload
9+
* @param {string} a
10+
* @param {boolean} b
11+
* @returns {string}
12+
*
13+
* @param {string | number} a
14+
* @param {string | number} b
15+
* @returns {string | number}
16+
*/
17+
export function overloaded(a,b) {
18+
>overloaded : Symbol(overloaded, Decl(overloadTag1.js, 0, 0))
19+
>a : Symbol(a, Decl(overloadTag1.js, 15, 27))
20+
>b : Symbol(b, Decl(overloadTag1.js, 15, 29))
21+
22+
if (typeof a === "string" && typeof b === "string") {
23+
>a : Symbol(a, Decl(overloadTag1.js, 15, 27))
24+
>b : Symbol(b, Decl(overloadTag1.js, 15, 29))
25+
26+
return a + b;
27+
>a : Symbol(a, Decl(overloadTag1.js, 15, 27))
28+
>b : Symbol(b, Decl(overloadTag1.js, 15, 29))
29+
30+
} else if (typeof a === "number" && typeof b === "number") {
31+
>a : Symbol(a, Decl(overloadTag1.js, 15, 27))
32+
>b : Symbol(b, Decl(overloadTag1.js, 15, 29))
33+
34+
return a + b;
35+
>a : Symbol(a, Decl(overloadTag1.js, 15, 27))
36+
>b : Symbol(b, Decl(overloadTag1.js, 15, 29))
37+
}
38+
throw new Error("Invalid arguments");
39+
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
40+
}
41+
var o1 = overloaded(1,2)
42+
>o1 : Symbol(o1, Decl(overloadTag1.js, 23, 3))
43+
>overloaded : Symbol(overloaded, Decl(overloadTag1.js, 0, 0))
44+
45+
var o2 = overloaded("zero", "one")
46+
>o2 : Symbol(o2, Decl(overloadTag1.js, 24, 3))
47+
>overloaded : Symbol(overloaded, Decl(overloadTag1.js, 0, 0))
48+
49+
var o3 = overloaded("a",false)
50+
>o3 : Symbol(o3, Decl(overloadTag1.js, 25, 3))
51+
>overloaded : Symbol(overloaded, Decl(overloadTag1.js, 0, 0))
52+
53+
/**
54+
* @overload
55+
* @param {number} a
56+
* @param {number} b
57+
* @returns {number}
58+
*
59+
* @overload
60+
* @param {string} a
61+
* @param {boolean} b
62+
* @returns {string}
63+
*/
64+
export function uncheckedInternally(a, b) {
65+
>uncheckedInternally : Symbol(uncheckedInternally, Decl(overloadTag1.js, 25, 30))
66+
>a : Symbol(a, Decl(overloadTag1.js, 38, 36))
67+
>b : Symbol(b, Decl(overloadTag1.js, 38, 38))
68+
69+
return a + b;
70+
>a : Symbol(a, Decl(overloadTag1.js, 38, 36))
71+
>b : Symbol(b, Decl(overloadTag1.js, 38, 38))
72+
}
73+
uncheckedInternally(1,2)
74+
>uncheckedInternally : Symbol(uncheckedInternally, Decl(overloadTag1.js, 25, 30))
75+
76+
uncheckedInternally("zero", "one")
77+
>uncheckedInternally : Symbol(uncheckedInternally, Decl(overloadTag1.js, 25, 30))
78+

0 commit comments

Comments
 (0)