mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-06 02:33:53 -06:00
fix(43160): improve error location for functions without explicit return (#43367)
* fix(43160): improve error location for functions without explicit return * handle functions returning never
This commit is contained in:
parent
3b06ef1a73
commit
3cf26e44ee
@ -30574,18 +30574,18 @@ namespace ts {
|
||||
}
|
||||
|
||||
const hasExplicitReturn = func.flags & NodeFlags.HasExplicitReturn;
|
||||
const errorNode = getEffectiveReturnTypeNode(func) || func;
|
||||
|
||||
if (type && type.flags & TypeFlags.Never) {
|
||||
error(getEffectiveReturnTypeNode(func), Diagnostics.A_function_returning_never_cannot_have_a_reachable_end_point);
|
||||
error(errorNode, Diagnostics.A_function_returning_never_cannot_have_a_reachable_end_point);
|
||||
}
|
||||
else if (type && !hasExplicitReturn) {
|
||||
// minimal check: function has syntactic return type annotation and no explicit return statements in the body
|
||||
// this function does not conform to the specification.
|
||||
// NOTE: having returnType !== undefined is a precondition for entering this branch so func.type will always be present
|
||||
error(getEffectiveReturnTypeNode(func), Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value);
|
||||
error(errorNode, Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value);
|
||||
}
|
||||
else if (type && strictNullChecks && !isTypeAssignableTo(undefinedType, type)) {
|
||||
error(getEffectiveReturnTypeNode(func) || func, Diagnostics.Function_lacks_ending_return_statement_and_return_type_does_not_include_undefined);
|
||||
error(errorNode, Diagnostics.Function_lacks_ending_return_statement_and_return_type_does_not_include_undefined);
|
||||
}
|
||||
else if (compilerOptions.noImplicitReturns) {
|
||||
if (!type) {
|
||||
@ -30600,7 +30600,7 @@ namespace ts {
|
||||
return;
|
||||
}
|
||||
}
|
||||
error(getEffectiveReturnTypeNode(func) || func, Diagnostics.Not_all_code_paths_return_a_value);
|
||||
error(errorNode, Diagnostics.Not_all_code_paths_return_a_value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,74 @@
|
||||
tests/cases/conformance/jsdoc/foo.js(7,10): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.
|
||||
tests/cases/conformance/jsdoc/foo.js(13,5): error TS2322: Type 'string' is not assignable to type 'number'.
|
||||
tests/cases/conformance/jsdoc/foo.js(16,60): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.
|
||||
tests/cases/conformance/jsdoc/foo.js(21,20): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.
|
||||
tests/cases/conformance/jsdoc/foo.js(31,10): error TS2534: A function returning 'never' cannot have a reachable end point.
|
||||
tests/cases/conformance/jsdoc/foo.js(37,5): error TS2322: Type 'string' is not assignable to type 'never'.
|
||||
tests/cases/conformance/jsdoc/foo.js(40,56): error TS2534: A function returning 'never' cannot have a reachable end point.
|
||||
tests/cases/conformance/jsdoc/foo.js(45,18): error TS2534: A function returning 'never' cannot have a reachable end point.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsdoc/foo.js (8 errors) ====
|
||||
/**
|
||||
* @callback FunctionReturningPromise
|
||||
* @returns {Promise<number>}
|
||||
*/
|
||||
|
||||
/** @type {FunctionReturningPromise} */
|
||||
function testPromise1() {
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.
|
||||
console.log("Nope");
|
||||
}
|
||||
|
||||
/** @type {FunctionReturningPromise} */
|
||||
async function testPromise2() {
|
||||
return "asd";
|
||||
~~~~~~~~~~~~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'number'.
|
||||
}
|
||||
|
||||
var testPromise3 = /** @type {FunctionReturningPromise} */ function() {
|
||||
~~~~~~~~
|
||||
!!! error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.
|
||||
console.log("test")
|
||||
}
|
||||
|
||||
/** @type {FunctionReturningPromise} */
|
||||
var testPromise4 = function() {
|
||||
~~~~~~~~
|
||||
!!! error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.
|
||||
console.log("test")
|
||||
}
|
||||
|
||||
/**
|
||||
* @callback FunctionReturningNever
|
||||
* @returns {never}
|
||||
*/
|
||||
|
||||
/** @type {FunctionReturningNever} */
|
||||
function testNever1() {
|
||||
~~~~~~~~~~
|
||||
!!! error TS2534: A function returning 'never' cannot have a reachable end point.
|
||||
|
||||
}
|
||||
|
||||
/** @type {FunctionReturningNever} */
|
||||
async function testNever2() {
|
||||
return "asd";
|
||||
~~~~~~~~~~~~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'never'.
|
||||
}
|
||||
|
||||
var testNever3 = /** @type {FunctionReturningNever} */ function() {
|
||||
~~~~~~~~
|
||||
!!! error TS2534: A function returning 'never' cannot have a reachable end point.
|
||||
console.log("test")
|
||||
}
|
||||
|
||||
/** @type {FunctionReturningNever} */
|
||||
var testNever4 = function() {
|
||||
~~~~~~~~
|
||||
!!! error TS2534: A function returning 'never' cannot have a reachable end point.
|
||||
console.log("test")
|
||||
}
|
||||
78
tests/baselines/reference/errorOnFunctionReturnType.symbols
Normal file
78
tests/baselines/reference/errorOnFunctionReturnType.symbols
Normal file
@ -0,0 +1,78 @@
|
||||
=== tests/cases/conformance/jsdoc/foo.js ===
|
||||
/**
|
||||
* @callback FunctionReturningPromise
|
||||
* @returns {Promise<number>}
|
||||
*/
|
||||
|
||||
/** @type {FunctionReturningPromise} */
|
||||
function testPromise1() {
|
||||
>testPromise1 : Symbol(testPromise1, Decl(foo.js, 0, 0))
|
||||
|
||||
console.log("Nope");
|
||||
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
}
|
||||
|
||||
/** @type {FunctionReturningPromise} */
|
||||
async function testPromise2() {
|
||||
>testPromise2 : Symbol(testPromise2, Decl(foo.js, 8, 1))
|
||||
|
||||
return "asd";
|
||||
}
|
||||
|
||||
var testPromise3 = /** @type {FunctionReturningPromise} */ function() {
|
||||
>testPromise3 : Symbol(testPromise3, Decl(foo.js, 15, 3))
|
||||
|
||||
console.log("test")
|
||||
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
}
|
||||
|
||||
/** @type {FunctionReturningPromise} */
|
||||
var testPromise4 = function() {
|
||||
>testPromise4 : Symbol(testPromise4, Decl(foo.js, 20, 3))
|
||||
|
||||
console.log("test")
|
||||
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
}
|
||||
|
||||
/**
|
||||
* @callback FunctionReturningNever
|
||||
* @returns {never}
|
||||
*/
|
||||
|
||||
/** @type {FunctionReturningNever} */
|
||||
function testNever1() {
|
||||
>testNever1 : Symbol(testNever1, Decl(foo.js, 22, 1))
|
||||
|
||||
}
|
||||
|
||||
/** @type {FunctionReturningNever} */
|
||||
async function testNever2() {
|
||||
>testNever2 : Symbol(testNever2, Decl(foo.js, 32, 1))
|
||||
|
||||
return "asd";
|
||||
}
|
||||
|
||||
var testNever3 = /** @type {FunctionReturningNever} */ function() {
|
||||
>testNever3 : Symbol(testNever3, Decl(foo.js, 39, 3))
|
||||
|
||||
console.log("test")
|
||||
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
}
|
||||
|
||||
/** @type {FunctionReturningNever} */
|
||||
var testNever4 = function() {
|
||||
>testNever4 : Symbol(testNever4, Decl(foo.js, 44, 3))
|
||||
|
||||
console.log("test")
|
||||
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
|
||||
}
|
||||
94
tests/baselines/reference/errorOnFunctionReturnType.types
Normal file
94
tests/baselines/reference/errorOnFunctionReturnType.types
Normal file
@ -0,0 +1,94 @@
|
||||
=== tests/cases/conformance/jsdoc/foo.js ===
|
||||
/**
|
||||
* @callback FunctionReturningPromise
|
||||
* @returns {Promise<number>}
|
||||
*/
|
||||
|
||||
/** @type {FunctionReturningPromise} */
|
||||
function testPromise1() {
|
||||
>testPromise1 : () => Promise<number>
|
||||
|
||||
console.log("Nope");
|
||||
>console.log("Nope") : void
|
||||
>console.log : (...data: any[]) => void
|
||||
>console : Console
|
||||
>log : (...data: any[]) => void
|
||||
>"Nope" : "Nope"
|
||||
}
|
||||
|
||||
/** @type {FunctionReturningPromise} */
|
||||
async function testPromise2() {
|
||||
>testPromise2 : () => Promise<number>
|
||||
|
||||
return "asd";
|
||||
>"asd" : "asd"
|
||||
}
|
||||
|
||||
var testPromise3 = /** @type {FunctionReturningPromise} */ function() {
|
||||
>testPromise3 : FunctionReturningPromise
|
||||
>function() { console.log("test")} : () => Promise<number>
|
||||
|
||||
console.log("test")
|
||||
>console.log("test") : void
|
||||
>console.log : (...data: any[]) => void
|
||||
>console : Console
|
||||
>log : (...data: any[]) => void
|
||||
>"test" : "test"
|
||||
}
|
||||
|
||||
/** @type {FunctionReturningPromise} */
|
||||
var testPromise4 = function() {
|
||||
>testPromise4 : FunctionReturningPromise
|
||||
>function() { console.log("test")} : () => Promise<number>
|
||||
|
||||
console.log("test")
|
||||
>console.log("test") : void
|
||||
>console.log : (...data: any[]) => void
|
||||
>console : Console
|
||||
>log : (...data: any[]) => void
|
||||
>"test" : "test"
|
||||
}
|
||||
|
||||
/**
|
||||
* @callback FunctionReturningNever
|
||||
* @returns {never}
|
||||
*/
|
||||
|
||||
/** @type {FunctionReturningNever} */
|
||||
function testNever1() {
|
||||
>testNever1 : () => never
|
||||
|
||||
}
|
||||
|
||||
/** @type {FunctionReturningNever} */
|
||||
async function testNever2() {
|
||||
>testNever2 : () => never
|
||||
|
||||
return "asd";
|
||||
>"asd" : "asd"
|
||||
}
|
||||
|
||||
var testNever3 = /** @type {FunctionReturningNever} */ function() {
|
||||
>testNever3 : FunctionReturningNever
|
||||
>function() { console.log("test")} : () => never
|
||||
|
||||
console.log("test")
|
||||
>console.log("test") : void
|
||||
>console.log : (...data: any[]) => void
|
||||
>console : Console
|
||||
>log : (...data: any[]) => void
|
||||
>"test" : "test"
|
||||
}
|
||||
|
||||
/** @type {FunctionReturningNever} */
|
||||
var testNever4 = function() {
|
||||
>testNever4 : FunctionReturningNever
|
||||
>function() { console.log("test")} : () => never
|
||||
|
||||
console.log("test")
|
||||
>console.log("test") : void
|
||||
>console.log : (...data: any[]) => void
|
||||
>console : Console
|
||||
>log : (...data: any[]) => void
|
||||
>"test" : "test"
|
||||
}
|
||||
52
tests/cases/conformance/jsdoc/errorOnFunctionReturnType.ts
Normal file
52
tests/cases/conformance/jsdoc/errorOnFunctionReturnType.ts
Normal file
@ -0,0 +1,52 @@
|
||||
// @noEmit: true
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @Filename: foo.js
|
||||
|
||||
/**
|
||||
* @callback FunctionReturningPromise
|
||||
* @returns {Promise<number>}
|
||||
*/
|
||||
|
||||
/** @type {FunctionReturningPromise} */
|
||||
function testPromise1() {
|
||||
console.log("Nope");
|
||||
}
|
||||
|
||||
/** @type {FunctionReturningPromise} */
|
||||
async function testPromise2() {
|
||||
return "asd";
|
||||
}
|
||||
|
||||
var testPromise3 = /** @type {FunctionReturningPromise} */ function() {
|
||||
console.log("test")
|
||||
}
|
||||
|
||||
/** @type {FunctionReturningPromise} */
|
||||
var testPromise4 = function() {
|
||||
console.log("test")
|
||||
}
|
||||
|
||||
/**
|
||||
* @callback FunctionReturningNever
|
||||
* @returns {never}
|
||||
*/
|
||||
|
||||
/** @type {FunctionReturningNever} */
|
||||
function testNever1() {
|
||||
|
||||
}
|
||||
|
||||
/** @type {FunctionReturningNever} */
|
||||
async function testNever2() {
|
||||
return "asd";
|
||||
}
|
||||
|
||||
var testNever3 = /** @type {FunctionReturningNever} */ function() {
|
||||
console.log("test")
|
||||
}
|
||||
|
||||
/** @type {FunctionReturningNever} */
|
||||
var testNever4 = function() {
|
||||
console.log("test")
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user