From 8619bff9c2a9448aa3b60874022c654802de3e1a Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 26 Sep 2019 13:51:24 -0700 Subject: [PATCH] Error on assertion and non-returning function calls that aren't CFA-ed --- src/compiler/binder.ts | 6 ------ src/compiler/checker.ts | 9 +++++++++ src/compiler/diagnosticMessages.json | 8 ++++++++ src/compiler/utilities.ts | 6 ++++++ 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 1d6627987e1..b2bc42d891d 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1287,12 +1287,6 @@ namespace ts { activeLabels!.pop(); } - function isDottedName(node: Expression): boolean { - return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisKeyword || - node.kind === SyntaxKind.PropertyAccessExpression && isDottedName((node).expression) || - node.kind === SyntaxKind.ParenthesizedExpression && isDottedName((node).expression); - } - function bindExpressionStatement(node: ExpressionStatement): void { bind(node.expression); // A top level call expression with a dotted function name and at least one argument diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7f3c1cfc43d..1a20173f4c2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23416,6 +23416,15 @@ namespace ts { if (returnType.flags & TypeFlags.ESSymbolLike && isSymbolOrSymbolForCall(node)) { return getESSymbolLikeTypeForNode(walkUpParenthesizedExpressions(node.parent)); } + if (node.kind === SyntaxKind.CallExpression && node.parent.kind === SyntaxKind.ExpressionStatement && + returnType.flags & (TypeFlags.Void | TypeFlags.Never) && hasTypePredicateOrNeverReturnType(signature)) { + if (!isDottedName(node.expression)) { + error(node.expression, Diagnostics.Control_flow_effects_of_calls_to_assertion_and_never_returning_functions_are_reflected_only_when_the_function_expression_is_an_identifier_or_qualified_name); + } + else if (!getEffectsSignature(node)) { + error(node.expression, Diagnostics.Control_flow_effects_of_calls_to_assertion_and_never_returning_functions_are_reflected_only_when_every_variable_or_property_referenced_in_the_function_expression_is_declared_with_an_explicit_type_annotation); + } + } let jsAssignmentType: Type | undefined; if (isInJSFile(node)) { const decl = getDeclarationOfExpando(node); diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 87052c4e7cd..056b02f7cb3 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2726,6 +2726,14 @@ "category": "Error", "code": 2774 }, + "Control flow effects of calls to assertion and never-returning functions are reflected only when every variable or property referenced in the function expression is declared with an explicit type annotation.": { + "category": "Error", + "code": 2775 + }, + "Control flow effects of calls to assertion and never-returning functions are reflected only when the function expression is an identifier or qualified-name.": { + "category": "Error", + "code": 2776 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", "code": 4000 diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 6b48cb80625..9a6fd48c08a 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -4062,6 +4062,12 @@ namespace ts { return node.kind === SyntaxKind.Identifier || isPropertyAccessEntityNameExpression(node); } + export function isDottedName(node: Expression): boolean { + return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisKeyword || + node.kind === SyntaxKind.PropertyAccessExpression && isDottedName((node).expression) || + node.kind === SyntaxKind.ParenthesizedExpression && isDottedName((node).expression); + } + export function isPropertyAccessEntityNameExpression(node: Node): node is PropertyAccessEntityNameExpression { return isPropertyAccessExpression(node) && isEntityNameExpression(node.expression); }