Skip to content
Open
8 changes: 8 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36286,6 +36286,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const nextTypes: Type[] = [];
const isAsync = (getFunctionFlags(func) & FunctionFlags.Async) !== 0;
forEachYieldExpression(func.body as Block, yieldExpression => {
const statement = findAncestor(yieldExpression, isStatement)!;
if (canHaveFlowNode(statement) && !statement.flowNode && !compilerOptions.allowUnreachableCode) {
return;
}
const yieldExpressionType = yieldExpression.expression ? checkExpression(yieldExpression.expression, checkMode) : undefinedWideningType;
pushIfUnique(yieldTypes, getYieldedTypeOfYieldExpression(yieldExpression, yieldExpressionType, anyType, isAsync));
let nextType: Type | undefined;
Expand Down Expand Up @@ -36393,6 +36397,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return;
}

if (!returnStatement.flowNode && !compilerOptions.allowUnreachableCode) {
return;
}

let type = checkExpressionCached(expr, checkMode && checkMode & ~CheckMode.SkipGenericFunctions);
if (functionFlags & FunctionFlags.Async) {
// From within an async function you can return either a non-promise value or a promise. Any
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/plainJSBinderErrors.types
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class C {
}
}
label() {
>label : () => number
>label : () => void

for(;;) {
label: var x = 1
Expand Down
10 changes: 5 additions & 5 deletions tests/baselines/reference/recursiveNamedLambdaCall.types
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ var promise = function( obj ) {
>doScroll : any

(function doScrollCheck() {
>(function doScrollCheck() { if ( false ) { try { top.doScroll("left"); } catch(e) { return setTimeout( doScrollCheck, 50 ); } // detach all dom ready events detach(); } })() : any
>(function doScrollCheck() { if ( false ) { try { top.doScroll("left"); } catch(e) { return setTimeout( doScrollCheck, 50 ); } // detach all dom ready events detach(); } }) : () => any
>function doScrollCheck() { if ( false ) { try { top.doScroll("left"); } catch(e) { return setTimeout( doScrollCheck, 50 ); } // detach all dom ready events detach(); } } : () => any
>doScrollCheck : () => any
>(function doScrollCheck() { if ( false ) { try { top.doScroll("left"); } catch(e) { return setTimeout( doScrollCheck, 50 ); } // detach all dom ready events detach(); } })() : void
>(function doScrollCheck() { if ( false ) { try { top.doScroll("left"); } catch(e) { return setTimeout( doScrollCheck, 50 ); } // detach all dom ready events detach(); } }) : () => void
>function doScrollCheck() { if ( false ) { try { top.doScroll("left"); } catch(e) { return setTimeout( doScrollCheck, 50 ); } // detach all dom ready events detach(); } } : () => void
>doScrollCheck : () => void

if ( false ) {
>false : false
Expand All @@ -36,7 +36,7 @@ var promise = function( obj ) {
return setTimeout( doScrollCheck, 50 );
>setTimeout( doScrollCheck, 50 ) : any
>setTimeout : any
>doScrollCheck : () => any
>doScrollCheck : () => void
>50 : 50
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

=== unreachable.js ===
function unreachable() {
>unreachable : () => void | 2 | 3 | 4
>unreachable : () => void

return f();
>f() : void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

=== unreachable.js ===
function unreachable() {
>unreachable : () => 1 | 2
>unreachable : () => number

return 1;
>1 : 1
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//// [tests/cases/compiler/unreachableReturnStatementsVsInferredReturnTypes.ts] ////

//// [unreachableReturnStatementsVsInferredReturnTypes.ts]
export function g() {
let x;
x = 1;
return x;
return x;
}

export function h() {
return 1;
let y;
y = 1;
return y;
}

export function i() {
let x: string | number | boolean;
x = 1;
return x;

x = "foo";
return x;
}


//// [unreachableReturnStatementsVsInferredReturnTypes.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.i = exports.h = exports.g = void 0;
function g() {
var x;
x = 1;
return x;
return x;
}
exports.g = g;
function h() {
return 1;
var y;
y = 1;
return y;
}
exports.h = h;
function i() {
var x;
x = 1;
return x;
x = "foo";
return x;
}
exports.i = i;


//// [unreachableReturnStatementsVsInferredReturnTypes.d.ts]
export declare function g(): number;
export declare function h(): number;
export declare function i(): number;
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//// [tests/cases/compiler/unreachableReturnStatementsVsInferredReturnTypes.ts] ////

=== unreachableReturnStatementsVsInferredReturnTypes.ts ===
export function g() {
>g : Symbol(g, Decl(unreachableReturnStatementsVsInferredReturnTypes.ts, 0, 0))

let x;
>x : Symbol(x, Decl(unreachableReturnStatementsVsInferredReturnTypes.ts, 1, 5))

x = 1;
>x : Symbol(x, Decl(unreachableReturnStatementsVsInferredReturnTypes.ts, 1, 5))

return x;
>x : Symbol(x, Decl(unreachableReturnStatementsVsInferredReturnTypes.ts, 1, 5))

return x;
>x : Symbol(x, Decl(unreachableReturnStatementsVsInferredReturnTypes.ts, 1, 5))
}

export function h() {
>h : Symbol(h, Decl(unreachableReturnStatementsVsInferredReturnTypes.ts, 5, 1))

return 1;
let y;
>y : Symbol(y, Decl(unreachableReturnStatementsVsInferredReturnTypes.ts, 9, 5))

y = 1;
>y : Symbol(y, Decl(unreachableReturnStatementsVsInferredReturnTypes.ts, 9, 5))

return y;
>y : Symbol(y, Decl(unreachableReturnStatementsVsInferredReturnTypes.ts, 9, 5))
}

export function i() {
>i : Symbol(i, Decl(unreachableReturnStatementsVsInferredReturnTypes.ts, 12, 1))

let x: string | number | boolean;
>x : Symbol(x, Decl(unreachableReturnStatementsVsInferredReturnTypes.ts, 15, 5))

x = 1;
>x : Symbol(x, Decl(unreachableReturnStatementsVsInferredReturnTypes.ts, 15, 5))

return x;
>x : Symbol(x, Decl(unreachableReturnStatementsVsInferredReturnTypes.ts, 15, 5))

x = "foo";
>x : Symbol(x, Decl(unreachableReturnStatementsVsInferredReturnTypes.ts, 15, 5))

return x;
>x : Symbol(x, Decl(unreachableReturnStatementsVsInferredReturnTypes.ts, 15, 5))
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//// [tests/cases/compiler/unreachableReturnStatementsVsInferredReturnTypes.ts] ////

=== unreachableReturnStatementsVsInferredReturnTypes.ts ===
export function g() {
>g : () => number

let x;
>x : any

x = 1;
>x = 1 : 1
>x : any
>1 : 1

return x;
>x : number

return x;
>x : any
}

export function h() {
>h : () => number

return 1;
>1 : 1

let y;
>y : any

y = 1;
>y = 1 : 1
>y : any
>1 : 1

return y;
>y : any
}

export function i() {
>i : () => number

let x: string | number | boolean;
>x : string | number | boolean

x = 1;
>x = 1 : 1
>x : string | number | boolean
>1 : 1

return x;
>x : number

x = "foo";
>x = "foo" : "foo"
>x : string | number | boolean
>"foo" : "foo"

return x;
>x : string | number | boolean
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//// [tests/cases/compiler/unreachableYieldExpressionsVsInferredYieldTypes.ts] ////

//// [unreachableYieldExpressionsVsInferredYieldTypes.ts]
export function* g() {
let x;
x = 1;
yield x;
return 'foo';
yield x;
}

export function* h() {
return 'foo';
let y;
y = 1;
yield y;
}

export function* i() {
yield true;
return 'foo';
let y;
y = 1;
yield y;
}

export function* j() {
let x: string | number | boolean;
x = 1;
yield x;
return true;

x = "foo";
yield x;
}


//// [unreachableYieldExpressionsVsInferredYieldTypes.js]
export function* g() {
let x;
x = 1;
yield x;
return 'foo';
yield x;
}
export function* h() {
return 'foo';
let y;
y = 1;
yield y;
}
export function* i() {
yield true;
return 'foo';
let y;
y = 1;
yield y;
}
export function* j() {
let x;
x = 1;
yield x;
return true;
x = "foo";
yield x;
}


//// [unreachableYieldExpressionsVsInferredYieldTypes.d.ts]
export declare function g(): Generator<number, string, unknown>;
export declare function h(): Generator<never, string, unknown>;
export declare function i(): Generator<boolean, string, unknown>;
export declare function j(): Generator<number, boolean, unknown>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//// [tests/cases/compiler/unreachableYieldExpressionsVsInferredYieldTypes.ts] ////

=== unreachableYieldExpressionsVsInferredYieldTypes.ts ===
export function* g() {
>g : Symbol(g, Decl(unreachableYieldExpressionsVsInferredYieldTypes.ts, 0, 0))

let x;
>x : Symbol(x, Decl(unreachableYieldExpressionsVsInferredYieldTypes.ts, 1, 5))

x = 1;
>x : Symbol(x, Decl(unreachableYieldExpressionsVsInferredYieldTypes.ts, 1, 5))

yield x;
>x : Symbol(x, Decl(unreachableYieldExpressionsVsInferredYieldTypes.ts, 1, 5))

return 'foo';
yield x;
>x : Symbol(x, Decl(unreachableYieldExpressionsVsInferredYieldTypes.ts, 1, 5))
}

export function* h() {
>h : Symbol(h, Decl(unreachableYieldExpressionsVsInferredYieldTypes.ts, 6, 1))

return 'foo';
let y;
>y : Symbol(y, Decl(unreachableYieldExpressionsVsInferredYieldTypes.ts, 10, 5))

y = 1;
>y : Symbol(y, Decl(unreachableYieldExpressionsVsInferredYieldTypes.ts, 10, 5))

yield y;
>y : Symbol(y, Decl(unreachableYieldExpressionsVsInferredYieldTypes.ts, 10, 5))
}

export function* i() {
>i : Symbol(i, Decl(unreachableYieldExpressionsVsInferredYieldTypes.ts, 13, 1))

yield true;
return 'foo';
let y;
>y : Symbol(y, Decl(unreachableYieldExpressionsVsInferredYieldTypes.ts, 18, 5))

y = 1;
>y : Symbol(y, Decl(unreachableYieldExpressionsVsInferredYieldTypes.ts, 18, 5))

yield y;
>y : Symbol(y, Decl(unreachableYieldExpressionsVsInferredYieldTypes.ts, 18, 5))
}

export function* j() {
>j : Symbol(j, Decl(unreachableYieldExpressionsVsInferredYieldTypes.ts, 21, 1))

let x: string | number | boolean;
>x : Symbol(x, Decl(unreachableYieldExpressionsVsInferredYieldTypes.ts, 24, 5))

x = 1;
>x : Symbol(x, Decl(unreachableYieldExpressionsVsInferredYieldTypes.ts, 24, 5))

yield x;
>x : Symbol(x, Decl(unreachableYieldExpressionsVsInferredYieldTypes.ts, 24, 5))

return true;

x = "foo";
>x : Symbol(x, Decl(unreachableYieldExpressionsVsInferredYieldTypes.ts, 24, 5))

yield x;
>x : Symbol(x, Decl(unreachableYieldExpressionsVsInferredYieldTypes.ts, 24, 5))
}

Loading