Skip to content

Commit

Permalink
Reduce types before checking if they are never
Browse files Browse the repository at this point in the history
When types are checked if they are `never` by their `TypeFlags`, they
must first be reduced, because intersection types of object-like types
which reduce to `never` don't have `TypeFlags.Never`. See microsoft#36696 for
details.

When a function is declared to return such type and it doesn't contain
any return statement or it only contains return statements without
expression, the error messages are incorrect as the checker sees its
return type as non-`never`.

This commit takes into account that intersection types potentially
reduces to `never` and improves error messages.
  • Loading branch information
lowr committed Feb 6, 2022
1 parent efe5e3d commit 0ffde2d
Showing 1 changed file with 6 additions and 3 deletions.
9 changes: 6 additions & 3 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32140,7 +32140,8 @@ namespace ts {
}

const functionFlags = getFunctionFlags(func);
const type = returnType && unwrapReturnType(returnType, functionFlags);
const unwrappedType = returnType && unwrapReturnType(returnType, functionFlags);
const type = unwrappedType && getReducedType(unwrappedType);

// Functions with with an explicitly specified 'void' or 'any' return type don't need any return expressions.
if (type && maybeTypeOfKind(type, TypeFlags.Any | TypeFlags.Void)) {
Expand All @@ -32157,7 +32158,9 @@ namespace ts {
const errorNode = getEffectiveReturnTypeNode(func) || func;

if (type && type.flags & TypeFlags.Never) {
error(errorNode, Diagnostics.A_function_returning_never_cannot_have_a_reachable_end_point);
const elaboration = elaborateNeverIntersection(/*errorInfo*/ undefined, unwrappedType);
const diagnostic = chainDiagnosticMessages(elaboration, Diagnostics.A_function_returning_never_cannot_have_a_reachable_end_point);
diagnostics.add(createDiagnosticForNodeFromMessageChain(errorNode, diagnostic));
}
else if (type && !hasExplicitReturn) {
// minimal check: function has syntactic return type annotation and no explicit return statements in the body
Expand Down Expand Up @@ -38219,7 +38222,7 @@ namespace ts {
const signature = getSignatureFromDeclaration(container);
const returnType = getReturnTypeOfSignature(signature);
const functionFlags = getFunctionFlags(container);
if (strictNullChecks || node.expression || returnType.flags & TypeFlags.Never) {
if (strictNullChecks || node.expression || returnType.flags & (TypeFlags.Never | TypeFlags.Intersection)) {
const exprType = node.expression ? checkExpressionCached(node.expression) : undefinedType;
if (container.kind === SyntaxKind.SetAccessor) {
if (node.expression) {
Expand Down

0 comments on commit 0ffde2d

Please sign in to comment.