Skip to content
Open
28 changes: 22 additions & 6 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6406,6 +6406,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
return !!annotationType && typeNodeIsEquivalentToType(node, type, annotationType) && existingTypeNodeIsNotReferenceOrIsReferenceWithCompatibleTypeArgumentCount(existing, type);
},

isPossiblyReachable(expression) {
const ancestor = findAncestor(expression, canHaveFlowNode);
if (!ancestor) {
return true;
}
return !!ancestor.flowNode && isReachableFlowNode(ancestor.flowNode);
},
};
return {
syntacticBuilderResolver,
Expand Down Expand Up @@ -39217,6 +39225,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 || !isReachableFlowNode(statement.flowNode))) {
return;
}
let yieldExpressionType = yieldExpression.expression ? checkExpression(yieldExpression.expression, checkMode) : undefinedWideningType;
if (yieldExpression.expression && isConstContext(yieldExpression.expression)) {
yieldExpressionType = getRegularTypeOfLiteralType(yieldExpressionType);
Expand Down Expand Up @@ -39336,6 +39348,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return;
}

if (!returnStatement.flowNode || !isReachableFlowNode(returnStatement.flowNode)) {
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 Expand Up @@ -42536,12 +42552,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {

checkDecorators(node);
checkSignatureDeclaration(node);
if (node.kind === SyntaxKind.GetAccessor) {
if (!(node.flags & NodeFlags.Ambient) && nodeIsPresent(node.body) && (node.flags & NodeFlags.HasImplicitReturn)) {
if (!(node.flags & NodeFlags.HasExplicitReturn)) {
error(node.name, Diagnostics.A_get_accessor_must_return_a_value);
}
}
if (
node.kind === SyntaxKind.GetAccessor && !(node.flags & NodeFlags.Ambient) && nodeIsPresent(node.body) &&
(node.flags & (NodeFlags.HasImplicitReturn | NodeFlags.HasExplicitReturn)) === NodeFlags.HasImplicitReturn &&
(!node.type || !(getTypeFromTypeNode(node.type).flags & TypeFlags.Never))
) {
error(node.name, Diagnostics.A_get_accessor_must_return_a_value);
}
// Do not use hasDynamicName here, because that returns false for well known symbols.
// We want to perform checkComputedPropertyName for all computed properties, including
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/expressionToTypeNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1305,7 +1305,7 @@ export function createSyntacticTypeNodeBuilder(
candidateExpr = body;
}
}
if (candidateExpr) {
if (candidateExpr && resolver.isPossiblyReachable(candidateExpr)) {
if (isContextuallyTyped(candidateExpr)) {
const type = isJSDocTypeAssertion(candidateExpr) ? getJSDocTypeAssertionType(candidateExpr) :
isAsExpression(candidateExpr) || isTypeAssertionExpression(candidateExpr) ? candidateExpr.type :
Expand Down
1 change: 1 addition & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10638,6 +10638,7 @@ export interface SyntacticTypeNodeBuilderResolver {
markError(): void;
hadError(): boolean;
};
isPossiblyReachable(expression: Expression): boolean;
}

/** @internal */
Expand Down
5 changes: 2 additions & 3 deletions src/server/editorServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3920,9 +3920,8 @@ export class ProjectService {
// Create sourceFileLike
if (!info.sourceFileLike) {
info.sourceFileLike = {
get text() {
Debug.fail("shouldnt need text");
return "";
get text(): never {
return Debug.fail("shouldnt need text");
},
getLineAndCharacterOfPosition: pos => {
const lineOffset = info.positionToLineOffset(pos);
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/bestCommonTypeReturnStatement.types
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ interface IPromise<T> {
}

function f() {
>f : () => IPromise<any>
> : ^^^^^^^^^^^^^^^^^^^
>f : () => IPromise<void>
> : ^^^^^^^^^^^^^^^^^^^^

if (true) return b();
>true : true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ var r4 = foo4(1);
> : ^

function foo5(x) {
>foo5 : (x: any) => 1 | 2
> : ^ ^^^^^^^^^^^^^^^
>foo5 : (x: any) => number
> : ^ ^^^^^^^^^^^^^^^^
>x : any

if (true) {
Expand All @@ -105,10 +105,10 @@ function foo5(x) {
var r5 = foo5(1);
>r5 : number
> : ^^^^^^
>foo5(1) : 1 | 2
> : ^^^^^
>foo5 : (x: any) => 1 | 2
> : ^ ^^^^^^^^^^^^^^^
>foo5(1) : number
> : ^^^^^^
>foo5 : (x: any) => number
> : ^ ^^^^^^^^^^^^^^^^
>1 : 1
> : ^

Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/duplicateLocalVariable1.types
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ export var tests: TestRunner = (function () {
> : ^^^^^^^^^^^^^^^
>"Test for any error" : "Test for any error"
> : ^^^^^^^^^^^^^^^^^^^^
>function () { throw new Error(); return false; } : () => false
>function () { throw new Error(); return false; } : () => never
> : ^^^^^^^^^^^
>new Error() : Error
> : ^^^^^
Expand All @@ -403,7 +403,7 @@ export var tests: TestRunner = (function () {
> : ^^^^^^^^^^^^^^^
>"Test RegEx error message match" : "Test RegEx error message match"
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>function () { throw new Error("Should also pass"); return false; } : () => false
>function () { throw new Error("Should also pass"); return false; } : () => never
> : ^^^^^^^^^^^
>new Error("Should also pass") : Error
> : ^^^^^
Expand Down
62 changes: 31 additions & 31 deletions tests/baselines/reference/functionImplementationErrors.types
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
=== functionImplementationErrors.ts ===
// FunctionExpression with no return type annotation with multiple return statements with unrelated types
var f1 = function () {
>f1 : () => "" | 3
>f1 : () => string
> : ^^^^^^^^^^^^
>function () { return ''; return 3;} : () => "" | 3
>function () { return ''; return 3;} : () => string
> : ^^^^^^^^^^^^

return '';
Expand All @@ -18,11 +18,11 @@ var f1 = function () {

};
var f2 = function x() {
>f2 : () => "" | 3
>f2 : () => string
> : ^^^^^^^^^^^^
>function x() { return ''; return 3;} : () => "" | 3
>function x() { return ''; return 3;} : () => string
> : ^^^^^^^^^^^^
>x : () => "" | 3
>x : () => string
> : ^^^^^^^^^^^^

return '';
Expand All @@ -35,9 +35,9 @@ var f2 = function x() {

};
var f3 = () => {
>f3 : () => "" | 3
>f3 : () => string
> : ^^^^^^^^^^^^
>() => { return ''; return 3;} : () => "" | 3
>() => { return ''; return 3;} : () => string
> : ^^^^^^^^^^^^

return '';
Expand All @@ -52,10 +52,10 @@ var f3 = () => {

// FunctionExpression with no return type annotation with return branch of number[] and other of string[]
var f4 = function () {
>f4 : () => string[] | number[]
> : ^^^^^^^^^^^^^^^^^^^^^^^^^
>function () { if (true) { return ['']; } else { return [1]; }} : () => string[] | number[]
> : ^^^^^^^^^^^^^^^^^^^^^^^^^
>f4 : () => string[]
> : ^^^^^^^^^^^^^^
>function () { if (true) { return ['']; } else { return [1]; }} : () => string[]
> : ^^^^^^^^^^^^^^

if (true) {
>true : true
Expand Down Expand Up @@ -165,8 +165,8 @@ class Derived2 extends Base { private n; }
> : ^^^

function f8() {
>f8 : () => Derived1 | Derived2
> : ^^^^^^^^^^^^^^^^^^^^^^^^^
>f8 : () => Derived1
> : ^^^^^^^^^^^^^^

return new Derived1();
>new Derived1() : Derived1
Expand All @@ -181,10 +181,10 @@ function f8() {
> : ^^^^^^^^^^^^^^^
}
var f9 = function () {
>f9 : () => Derived1 | Derived2
> : ^^^^^^^^^^^^^^^^^^^^^^^^^
>function () { return new Derived1(); return new Derived2();} : () => Derived1 | Derived2
> : ^^^^^^^^^^^^^^^^^^^^^^^^^
>f9 : () => Derived1
> : ^^^^^^^^^^^^^^
>function () { return new Derived1(); return new Derived2();} : () => Derived1
> : ^^^^^^^^^^^^^^

return new Derived1();
>new Derived1() : Derived1
Expand All @@ -200,10 +200,10 @@ var f9 = function () {

};
var f10 = () => {
>f10 : () => Derived1 | Derived2
> : ^^^^^^^^^^^^^^^^^^^^^^^^^
>() => { return new Derived1(); return new Derived2();} : () => Derived1 | Derived2
> : ^^^^^^^^^^^^^^^^^^^^^^^^^
>f10 : () => Derived1
> : ^^^^^^^^^^^^^^
>() => { return new Derived1(); return new Derived2();} : () => Derived1
> : ^^^^^^^^^^^^^^

return new Derived1();
>new Derived1() : Derived1
Expand All @@ -219,8 +219,8 @@ var f10 = () => {

};
function f11() {
>f11 : () => Base | AnotherClass
> : ^^^^^^^^^^^^^^^^^^^^^^^^^
>f11 : () => Base
> : ^^^^^^^^^^

return new Base();
>new Base() : Base
Expand All @@ -235,10 +235,10 @@ function f11() {
> : ^^^^^^^^^^^^^^^^^^^
}
var f12 = function () {
>f12 : () => Base | AnotherClass
> : ^^^^^^^^^^^^^^^^^^^^^^^^^
>function () { return new Base(); return new AnotherClass();} : () => Base | AnotherClass
> : ^^^^^^^^^^^^^^^^^^^^^^^^^
>f12 : () => Base
> : ^^^^^^^^^^
>function () { return new Base(); return new AnotherClass();} : () => Base
> : ^^^^^^^^^^

return new Base();
>new Base() : Base
Expand All @@ -254,10 +254,10 @@ var f12 = function () {

};
var f13 = () => {
>f13 : () => Base | AnotherClass
> : ^^^^^^^^^^^^^^^^^^^^^^^^^
>() => { return new Base(); return new AnotherClass();} : () => Base | AnotherClass
> : ^^^^^^^^^^^^^^^^^^^^^^^^^
>f13 : () => Base
> : ^^^^^^^^^^
>() => { return new Base(); return new AnotherClass();} : () => Base
> : ^^^^^^^^^^

return new Base();
>new Base() : Base
Expand Down
20 changes: 10 additions & 10 deletions tests/baselines/reference/functionImplementations.types
Original file line number Diff line number Diff line change
Expand Up @@ -233,10 +233,10 @@ var n = function <T extends {}>(x: T) {
var n = function () {
>n : number
> : ^^^^^^
>function () { return 3; return 5;}() : 3 | 5
> : ^^^^^
>function () { return 3; return 5;} : () => 3 | 5
> : ^^^^^^^^^^^
>function () { return 3; return 5;}() : number
> : ^^^^^^
>function () { return 3; return 5;} : () => number
> : ^^^^^^^^^^^^

return 3;
>3 : 3
Expand Down Expand Up @@ -534,8 +534,8 @@ var f10: (x: number) => any = x => { // should be (x: number) => Derived | Deriv
> : ^ ^^ ^^^^^
>x : number
> : ^^^^^^
>x => { // should be (x: number) => Derived | Derived1 return new Derived(); return new Derived2();} : (x: number) => Derived | Derived2
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>x => { // should be (x: number) => Derived | Derived1 return new Derived(); return new Derived2();} : (x: number) => Derived
> : ^ ^^^^^^^^^^^^^^^^^^^^
>x : number
> : ^^^^^^

Expand All @@ -556,8 +556,8 @@ var f11: (x: number) => any = x => { // should be (x: number) => Base | AnotherC
> : ^ ^^ ^^^^^
>x : number
> : ^^^^^^
>x => { // should be (x: number) => Base | AnotherClass return new Base(); return new AnotherClass();} : (x: number) => Base | AnotherClass
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>x => { // should be (x: number) => Base | AnotherClass return new Base(); return new AnotherClass();} : (x: number) => Base
> : ^ ^^^^^^^^^^^^^^^^^
>x : number
> : ^^^^^^

Expand All @@ -578,8 +578,8 @@ var f12: (x: number) => any = x => { // should be (x: number) => Base | AnotherC
> : ^ ^^ ^^^^^
>x : number
> : ^^^^^^
>x => { // should be (x: number) => Base | AnotherClass return new Base(); return; // should be ignored return new AnotherClass();} : (x: number) => Base | AnotherClass
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>x => { // should be (x: number) => Base | AnotherClass return new Base(); return; // should be ignored return new AnotherClass();} : (x: number) => Base
> : ^ ^^^^^^^^^^^^^^^^^
>x : number
> : ^^^^^^

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// it is an error if there is no single BCT, these are error cases

function f1() {
>f1 : () => 1 | ""
>f1 : () => number
> : ^^^^^^^^^^^^

if (true) {
Expand All @@ -24,8 +24,8 @@ function f1() {
}

function f2() {
>f2 : () => 1 | "" | 2
> : ^^^^^^^^^^^^^^^^
>f2 : () => number
> : ^^^^^^^^^^^^

if (true) {
>true : true
Expand Down Expand Up @@ -89,7 +89,7 @@ function f4() {
}

function f5() {
>f5 : () => 1 | ""
>f5 : () => number
> : ^^^^^^^^^^^^

return 1;
Expand All @@ -102,8 +102,8 @@ function f5() {
}

function f6<T, U>(x: T, y:U) {
>f6 : <T, U>(x: T, y: U) => T | U
> : ^ ^^ ^^ ^^ ^^ ^^ ^^^^^^^^^^
>f6 : <T, U>(x: T, y: U) => T
> : ^ ^^ ^^ ^^ ^^ ^^ ^^^^^^
>x : T
> : ^
>y : U
Expand All @@ -125,7 +125,7 @@ function f6<T, U>(x: T, y:U) {
}

function f8<T extends U, U extends V, V>(x: T, y: U) {
>f8 : <T extends U, U extends V, V>(x: T, y: U) => U
>f8 : <T extends U, U extends V, V>(x: T, y: U) => T
> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^^^^^
>x : T
> : ^
Expand Down
Loading