From 8619bff9c2a9448aa3b60874022c654802de3e1a Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 26 Sep 2019 13:51:24 -0700 Subject: [PATCH 1/9] 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 1d6627987e151..b2bc42d891d86 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 7f3c1cfc43d16..1a20173f4c261 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 87052c4e7cdb2..056b02f7cb3ce 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 6b48cb80625ee..9a6fd48c08af7 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); } From 894cc63be1895c0ac1d000d89454d7d9ddf51cc7 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 26 Sep 2019 13:51:32 -0700 Subject: [PATCH 2/9] Add tests --- .../controlFlow/assertionTypePredicates1.ts | 11 +++++++++++ .../controlFlow/neverReturningFunctions1.ts | 7 +++++++ 2 files changed, 18 insertions(+) diff --git a/tests/cases/conformance/controlFlow/assertionTypePredicates1.ts b/tests/cases/conformance/controlFlow/assertionTypePredicates1.ts index b20cd42414b53..4cc73d5c91758 100644 --- a/tests/cases/conformance/controlFlow/assertionTypePredicates1.ts +++ b/tests/cases/conformance/controlFlow/assertionTypePredicates1.ts @@ -126,3 +126,14 @@ declare class Wat { get p2(): asserts this is string; set p2(x: asserts this is string); } + +function f20(x: unknown) { + const assert = (value: unknown): asserts value => {} + assert(typeof x === "string"); // Error + const a = [assert]; + a[0](typeof x === "string"); // Error + const t1 = new Test(); + t1.assert(typeof x === "string"); // Error + const t2: Test = new Test(); + t2.assert(typeof x === "string"); +} diff --git a/tests/cases/conformance/controlFlow/neverReturningFunctions1.ts b/tests/cases/conformance/controlFlow/neverReturningFunctions1.ts index 72dd0a13b5ae0..e1e0d43de4bf6 100644 --- a/tests/cases/conformance/controlFlow/neverReturningFunctions1.ts +++ b/tests/cases/conformance/controlFlow/neverReturningFunctions1.ts @@ -157,6 +157,13 @@ function f42(x: number) { x; // Unreachable } +function f43() { + const fail = (): never => { throw new Error(); }; + const f = [fail]; + fail(); // Error + f[0](); // Error +} + // Repro from #33582 export interface Component { From 0595d6160618935b586e27a128a3a3db876b5888 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 26 Sep 2019 14:00:00 -0700 Subject: [PATCH 3/9] Accept new baselines --- .../assertionTypePredicates1.errors.txt | 22 ++- .../reference/assertionTypePredicates1.js | 22 +++ .../assertionTypePredicates1.symbols | 43 +++++ .../reference/assertionTypePredicates1.types | 63 ++++++ .../neverReturningFunctions1.errors.txt | 15 +- .../reference/neverReturningFunctions1.js | 13 ++ .../neverReturningFunctions1.symbols | 180 ++++++++++-------- .../reference/neverReturningFunctions1.types | 25 +++ 8 files changed, 300 insertions(+), 83 deletions(-) diff --git a/tests/baselines/reference/assertionTypePredicates1.errors.txt b/tests/baselines/reference/assertionTypePredicates1.errors.txt index 91d2e869bd2e2..68253ff06b65c 100644 --- a/tests/baselines/reference/assertionTypePredicates1.errors.txt +++ b/tests/baselines/reference/assertionTypePredicates1.errors.txt @@ -5,9 +5,12 @@ tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(121,15): error T tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(122,15): error TS1228: A type predicate is only allowed in return type position for functions and methods. tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(123,15): error TS1228: A type predicate is only allowed in return type position for functions and methods. tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(124,15): error TS1228: A type predicate is only allowed in return type position for functions and methods. +tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(129,5): error TS2775: 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. +tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(131,5): error TS2776: Control flow effects of calls to assertion and never-returning functions are reflected only when the function expression is an identifier or qualified-name. +tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(133,5): error TS2775: 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. -==== tests/cases/conformance/controlFlow/assertionTypePredicates1.ts (7 errors) ==== +==== tests/cases/conformance/controlFlow/assertionTypePredicates1.ts (10 errors) ==== declare function isString(value: unknown): value is string; declare function isArrayOfStrings(value: unknown): value is string[]; @@ -147,4 +150,21 @@ tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(124,15): error T ~~~~~~~~~~~~~~~~~~~~~~ !!! error TS1228: A type predicate is only allowed in return type position for functions and methods. } + + function f20(x: unknown) { + const assert = (value: unknown): asserts value => {} + assert(typeof x === "string"); // Error + ~~~~~~ +!!! error TS2775: 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. + const a = [assert]; + a[0](typeof x === "string"); // Error + ~~~~ +!!! error TS2776: Control flow effects of calls to assertion and never-returning functions are reflected only when the function expression is an identifier or qualified-name. + const t1 = new Test(); + t1.assert(typeof x === "string"); // Error + ~~~~~~~~~ +!!! error TS2775: 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. + const t2: Test = new Test(); + t2.assert(typeof x === "string"); + } \ No newline at end of file diff --git a/tests/baselines/reference/assertionTypePredicates1.js b/tests/baselines/reference/assertionTypePredicates1.js index ad21d116b73ab..145bb98bce980 100644 --- a/tests/baselines/reference/assertionTypePredicates1.js +++ b/tests/baselines/reference/assertionTypePredicates1.js @@ -124,6 +124,17 @@ declare class Wat { get p2(): asserts this is string; set p2(x: asserts this is string); } + +function f20(x: unknown) { + const assert = (value: unknown): asserts value => {} + assert(typeof x === "string"); // Error + const a = [assert]; + a[0](typeof x === "string"); // Error + const t1 = new Test(); + t1.assert(typeof x === "string"); // Error + const t2: Test = new Test(); + t2.assert(typeof x === "string"); +} //// [assertionTypePredicates1.js] @@ -250,6 +261,16 @@ var Test2 = /** @class */ (function (_super) { } return Test2; }(Test)); +function f20(x) { + var assert = function (value) { }; + assert(typeof x === "string"); // Error + var a = [assert]; + a[0](typeof x === "string"); // Error + var t1 = new Test(); + t1.assert(typeof x === "string"); // Error + var t2 = new Test(); + t2.assert(typeof x === "string"); +} //// [assertionTypePredicates1.d.ts] @@ -287,3 +308,4 @@ declare class Wat { get p2(): asserts this is string; set p2(x: asserts this is string); } +declare function f20(x: unknown): void; diff --git a/tests/baselines/reference/assertionTypePredicates1.symbols b/tests/baselines/reference/assertionTypePredicates1.symbols index c68a1926aff49..af43ab29864e1 100644 --- a/tests/baselines/reference/assertionTypePredicates1.symbols +++ b/tests/baselines/reference/assertionTypePredicates1.symbols @@ -357,3 +357,46 @@ declare class Wat { >x : Symbol(x, Decl(assertionTypePredicates1.ts, 123, 11)) } +function f20(x: unknown) { +>f20 : Symbol(f20, Decl(assertionTypePredicates1.ts, 124, 1)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 126, 13)) + + const assert = (value: unknown): asserts value => {} +>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 127, 9)) +>value : Symbol(value, Decl(assertionTypePredicates1.ts, 127, 20)) +>value : Symbol(value, Decl(assertionTypePredicates1.ts, 127, 20)) + + assert(typeof x === "string"); // Error +>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 127, 9)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 126, 13)) + + const a = [assert]; +>a : Symbol(a, Decl(assertionTypePredicates1.ts, 129, 9)) +>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 127, 9)) + + a[0](typeof x === "string"); // Error +>a : Symbol(a, Decl(assertionTypePredicates1.ts, 129, 9)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 126, 13)) + + const t1 = new Test(); +>t1 : Symbol(t1, Decl(assertionTypePredicates1.ts, 131, 9)) +>Test : Symbol(Test, Decl(assertionTypePredicates1.ts, 76, 1)) + + t1.assert(typeof x === "string"); // Error +>t1.assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 78, 12)) +>t1 : Symbol(t1, Decl(assertionTypePredicates1.ts, 131, 9)) +>assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 78, 12)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 126, 13)) + + const t2: Test = new Test(); +>t2 : Symbol(t2, Decl(assertionTypePredicates1.ts, 133, 9)) +>Test : Symbol(Test, Decl(assertionTypePredicates1.ts, 76, 1)) +>Test : Symbol(Test, Decl(assertionTypePredicates1.ts, 76, 1)) + + t2.assert(typeof x === "string"); +>t2.assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 78, 12)) +>t2 : Symbol(t2, Decl(assertionTypePredicates1.ts, 133, 9)) +>assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 78, 12)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 126, 13)) +} + diff --git a/tests/baselines/reference/assertionTypePredicates1.types b/tests/baselines/reference/assertionTypePredicates1.types index f72ec641013aa..470478b3fe48c 100644 --- a/tests/baselines/reference/assertionTypePredicates1.types +++ b/tests/baselines/reference/assertionTypePredicates1.types @@ -436,3 +436,66 @@ declare class Wat { >x : void } +function f20(x: unknown) { +>f20 : (x: unknown) => void +>x : unknown + + const assert = (value: unknown): asserts value => {} +>assert : (value: unknown) => asserts value +>(value: unknown): asserts value => {} : (value: unknown) => asserts value +>value : unknown + + assert(typeof x === "string"); // Error +>assert(typeof x === "string") : void +>assert : (value: unknown) => asserts value +>typeof x === "string" : boolean +>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>x : unknown +>"string" : "string" + + const a = [assert]; +>a : ((value: unknown) => asserts value)[] +>[assert] : ((value: unknown) => asserts value)[] +>assert : (value: unknown) => asserts value + + a[0](typeof x === "string"); // Error +>a[0](typeof x === "string") : void +>a[0] : (value: unknown) => asserts value +>a : ((value: unknown) => asserts value)[] +>0 : 0 +>typeof x === "string" : boolean +>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>x : unknown +>"string" : "string" + + const t1 = new Test(); +>t1 : Test +>new Test() : Test +>Test : typeof Test + + t1.assert(typeof x === "string"); // Error +>t1.assert(typeof x === "string") : void +>t1.assert : (value: unknown) => asserts value +>t1 : Test +>assert : (value: unknown) => asserts value +>typeof x === "string" : boolean +>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>x : unknown +>"string" : "string" + + const t2: Test = new Test(); +>t2 : Test +>new Test() : Test +>Test : typeof Test + + t2.assert(typeof x === "string"); +>t2.assert(typeof x === "string") : void +>t2.assert : (value: unknown) => asserts value +>t2 : Test +>assert : (value: unknown) => asserts value +>typeof x === "string" : boolean +>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>x : unknown +>"string" : "string" +} + diff --git a/tests/baselines/reference/neverReturningFunctions1.errors.txt b/tests/baselines/reference/neverReturningFunctions1.errors.txt index 5eb6659427c46..5c6ba45ea4ab8 100644 --- a/tests/baselines/reference/neverReturningFunctions1.errors.txt +++ b/tests/baselines/reference/neverReturningFunctions1.errors.txt @@ -21,9 +21,11 @@ tests/cases/conformance/controlFlow/neverReturningFunctions1.ts(139,9): error TS tests/cases/conformance/controlFlow/neverReturningFunctions1.ts(141,5): error TS7027: Unreachable code detected. tests/cases/conformance/controlFlow/neverReturningFunctions1.ts(148,9): error TS7027: Unreachable code detected. tests/cases/conformance/controlFlow/neverReturningFunctions1.ts(153,5): error TS7027: Unreachable code detected. +tests/cases/conformance/controlFlow/neverReturningFunctions1.ts(159,5): error TS2775: 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. +tests/cases/conformance/controlFlow/neverReturningFunctions1.ts(160,5): error TS2776: Control flow effects of calls to assertion and never-returning functions are reflected only when the function expression is an identifier or qualified-name. -==== tests/cases/conformance/controlFlow/neverReturningFunctions1.ts (23 errors) ==== +==== tests/cases/conformance/controlFlow/neverReturningFunctions1.ts (25 errors) ==== function fail(message?: string): never { throw new Error(message); } @@ -225,6 +227,17 @@ tests/cases/conformance/controlFlow/neverReturningFunctions1.ts(153,5): error TS !!! error TS7027: Unreachable code detected. } + function f43() { + const fail = (): never => { throw new Error(); }; + const f = [fail]; + fail(); // Error + ~~~~ +!!! error TS2775: 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. + f[0](); // Error + ~~~~ +!!! error TS2776: Control flow effects of calls to assertion and never-returning functions are reflected only when the function expression is an identifier or qualified-name. + } + // Repro from #33582 export interface Component { diff --git a/tests/baselines/reference/neverReturningFunctions1.js b/tests/baselines/reference/neverReturningFunctions1.js index a99cc51e06dad..dc79d7733dff1 100644 --- a/tests/baselines/reference/neverReturningFunctions1.js +++ b/tests/baselines/reference/neverReturningFunctions1.js @@ -154,6 +154,13 @@ function f42(x: number) { x; // Unreachable } +function f43() { + const fail = (): never => { throw new Error(); }; + const f = [fail]; + fail(); // Error + f[0](); // Error +} + // Repro from #33582 export interface Component { @@ -375,6 +382,12 @@ function f42(x) { } x; // Unreachable } +function f43() { + var fail = function () { throw new Error(); }; + var f = [fail]; + fail(); // Error + f[0](); // Error +} var Component = registerComponent('test-component', { schema: { myProperty: { diff --git a/tests/baselines/reference/neverReturningFunctions1.symbols b/tests/baselines/reference/neverReturningFunctions1.symbols index 2ec4c5f93d38a..3dff8bef7e32b 100644 --- a/tests/baselines/reference/neverReturningFunctions1.symbols +++ b/tests/baselines/reference/neverReturningFunctions1.symbols @@ -385,196 +385,214 @@ function f42(x: number) { >x : Symbol(x, Decl(neverReturningFunctions1.ts, 143, 13)) } +function f43() { +>f43 : Symbol(f43, Decl(neverReturningFunctions1.ts, 153, 1)) + + const fail = (): never => { throw new Error(); }; +>fail : Symbol(fail, Decl(neverReturningFunctions1.ts, 156, 9)) +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + + const f = [fail]; +>f : Symbol(f, Decl(neverReturningFunctions1.ts, 157, 9)) +>fail : Symbol(fail, Decl(neverReturningFunctions1.ts, 156, 9)) + + fail(); // Error +>fail : Symbol(fail, Decl(neverReturningFunctions1.ts, 156, 9)) + + f[0](); // Error +>f : Symbol(f, Decl(neverReturningFunctions1.ts, 157, 9)) +} + // Repro from #33582 export interface Component { ->Component : Symbol(Component, Decl(neverReturningFunctions1.ts, 153, 1)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 157, 27)) +>Component : Symbol(Component, Decl(neverReturningFunctions1.ts, 160, 1)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 164, 27)) attrName?: string; ->attrName : Symbol(Component.attrName, Decl(neverReturningFunctions1.ts, 157, 52)) +>attrName : Symbol(Component.attrName, Decl(neverReturningFunctions1.ts, 164, 52)) data: T; ->data : Symbol(Component.data, Decl(neverReturningFunctions1.ts, 158, 19)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 157, 27)) +>data : Symbol(Component.data, Decl(neverReturningFunctions1.ts, 165, 19)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 164, 27)) dependencies?: string[]; ->dependencies : Symbol(Component.dependencies, Decl(neverReturningFunctions1.ts, 159, 9)) +>dependencies : Symbol(Component.dependencies, Decl(neverReturningFunctions1.ts, 166, 9)) el: any; ->el : Symbol(Component.el, Decl(neverReturningFunctions1.ts, 160, 25)) +>el : Symbol(Component.el, Decl(neverReturningFunctions1.ts, 167, 25)) id: string; ->id : Symbol(Component.id, Decl(neverReturningFunctions1.ts, 161, 9)) +>id : Symbol(Component.id, Decl(neverReturningFunctions1.ts, 168, 9)) multiple?: boolean; ->multiple : Symbol(Component.multiple, Decl(neverReturningFunctions1.ts, 162, 12)) +>multiple : Symbol(Component.multiple, Decl(neverReturningFunctions1.ts, 169, 12)) name: string; ->name : Symbol(Component.name, Decl(neverReturningFunctions1.ts, 163, 20)) +>name : Symbol(Component.name, Decl(neverReturningFunctions1.ts, 170, 20)) schema: unknown; ->schema : Symbol(Component.schema, Decl(neverReturningFunctions1.ts, 164, 14)) +>schema : Symbol(Component.schema, Decl(neverReturningFunctions1.ts, 171, 14)) system: any; ->system : Symbol(Component.system, Decl(neverReturningFunctions1.ts, 165, 17)) +>system : Symbol(Component.system, Decl(neverReturningFunctions1.ts, 172, 17)) init(data?: T): void; ->init : Symbol(Component.init, Decl(neverReturningFunctions1.ts, 166, 13)) ->data : Symbol(data, Decl(neverReturningFunctions1.ts, 168, 6)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 157, 27)) +>init : Symbol(Component.init, Decl(neverReturningFunctions1.ts, 173, 13)) +>data : Symbol(data, Decl(neverReturningFunctions1.ts, 175, 6)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 164, 27)) pause(): void; ->pause : Symbol(Component.pause, Decl(neverReturningFunctions1.ts, 168, 22)) +>pause : Symbol(Component.pause, Decl(neverReturningFunctions1.ts, 175, 22)) play(): void; ->play : Symbol(Component.play, Decl(neverReturningFunctions1.ts, 169, 15)) +>play : Symbol(Component.play, Decl(neverReturningFunctions1.ts, 176, 15)) remove(): void; ->remove : Symbol(Component.remove, Decl(neverReturningFunctions1.ts, 170, 14)) +>remove : Symbol(Component.remove, Decl(neverReturningFunctions1.ts, 177, 14)) tick?(time: number, timeDelta: number): void; ->tick : Symbol(Component.tick, Decl(neverReturningFunctions1.ts, 171, 16)) ->time : Symbol(time, Decl(neverReturningFunctions1.ts, 172, 7)) ->timeDelta : Symbol(timeDelta, Decl(neverReturningFunctions1.ts, 172, 20)) +>tick : Symbol(Component.tick, Decl(neverReturningFunctions1.ts, 178, 16)) +>time : Symbol(time, Decl(neverReturningFunctions1.ts, 179, 7)) +>timeDelta : Symbol(timeDelta, Decl(neverReturningFunctions1.ts, 179, 20)) update(oldData: T): void; ->update : Symbol(Component.update, Decl(neverReturningFunctions1.ts, 172, 46)) ->oldData : Symbol(oldData, Decl(neverReturningFunctions1.ts, 173, 8)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 157, 27)) +>update : Symbol(Component.update, Decl(neverReturningFunctions1.ts, 179, 46)) +>oldData : Symbol(oldData, Decl(neverReturningFunctions1.ts, 180, 8)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 164, 27)) updateSchema?(): void; ->updateSchema : Symbol(Component.updateSchema, Decl(neverReturningFunctions1.ts, 173, 26)) +>updateSchema : Symbol(Component.updateSchema, Decl(neverReturningFunctions1.ts, 180, 26)) extendSchema(update: unknown): void; ->extendSchema : Symbol(Component.extendSchema, Decl(neverReturningFunctions1.ts, 174, 23)) ->update : Symbol(update, Decl(neverReturningFunctions1.ts, 176, 14)) +>extendSchema : Symbol(Component.extendSchema, Decl(neverReturningFunctions1.ts, 181, 23)) +>update : Symbol(update, Decl(neverReturningFunctions1.ts, 183, 14)) flushToDOM(): void; ->flushToDOM : Symbol(Component.flushToDOM, Decl(neverReturningFunctions1.ts, 176, 37)) +>flushToDOM : Symbol(Component.flushToDOM, Decl(neverReturningFunctions1.ts, 183, 37)) } export interface ComponentConstructor { ->ComponentConstructor : Symbol(ComponentConstructor, Decl(neverReturningFunctions1.ts, 178, 1)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 180, 38)) +>ComponentConstructor : Symbol(ComponentConstructor, Decl(neverReturningFunctions1.ts, 185, 1)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 187, 38)) new (el: unknown, attrValue: string, id: string): T & Component; ->el : Symbol(el, Decl(neverReturningFunctions1.ts, 181, 6)) ->attrValue : Symbol(attrValue, Decl(neverReturningFunctions1.ts, 181, 18)) ->id : Symbol(id, Decl(neverReturningFunctions1.ts, 181, 37)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 180, 38)) ->Component : Symbol(Component, Decl(neverReturningFunctions1.ts, 153, 1)) +>el : Symbol(el, Decl(neverReturningFunctions1.ts, 188, 6)) +>attrValue : Symbol(attrValue, Decl(neverReturningFunctions1.ts, 188, 18)) +>id : Symbol(id, Decl(neverReturningFunctions1.ts, 188, 37)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 187, 38)) +>Component : Symbol(Component, Decl(neverReturningFunctions1.ts, 160, 1)) prototype: T & { ->prototype : Symbol(ComponentConstructor.prototype, Decl(neverReturningFunctions1.ts, 181, 65)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 180, 38)) +>prototype : Symbol(ComponentConstructor.prototype, Decl(neverReturningFunctions1.ts, 188, 65)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 187, 38)) name: string; ->name : Symbol(name, Decl(neverReturningFunctions1.ts, 182, 17)) +>name : Symbol(name, Decl(neverReturningFunctions1.ts, 189, 17)) system: unknown; ->system : Symbol(system, Decl(neverReturningFunctions1.ts, 183, 15)) +>system : Symbol(system, Decl(neverReturningFunctions1.ts, 190, 15)) play(): void; ->play : Symbol(play, Decl(neverReturningFunctions1.ts, 184, 18)) +>play : Symbol(play, Decl(neverReturningFunctions1.ts, 191, 18)) pause(): void; ->pause : Symbol(pause, Decl(neverReturningFunctions1.ts, 185, 15)) +>pause : Symbol(pause, Decl(neverReturningFunctions1.ts, 192, 15)) }; } declare function registerComponent( ->registerComponent : Symbol(registerComponent, Decl(neverReturningFunctions1.ts, 188, 1)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 190, 35)) +>registerComponent : Symbol(registerComponent, Decl(neverReturningFunctions1.ts, 195, 1)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 197, 35)) name: string, ->name : Symbol(name, Decl(neverReturningFunctions1.ts, 190, 53)) +>name : Symbol(name, Decl(neverReturningFunctions1.ts, 197, 53)) component: ComponentDefinition ->component : Symbol(component, Decl(neverReturningFunctions1.ts, 191, 17)) ->ComponentDefinition : Symbol(ComponentDefinition, Decl(neverReturningFunctions1.ts, 193, 27)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 190, 35)) +>component : Symbol(component, Decl(neverReturningFunctions1.ts, 198, 17)) +>ComponentDefinition : Symbol(ComponentDefinition, Decl(neverReturningFunctions1.ts, 200, 27)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 197, 35)) ): ComponentConstructor; ->ComponentConstructor : Symbol(ComponentConstructor, Decl(neverReturningFunctions1.ts, 178, 1)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 190, 35)) +>ComponentConstructor : Symbol(ComponentConstructor, Decl(neverReturningFunctions1.ts, 185, 1)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 197, 35)) export type ComponentDefinition = T & Partial & ThisType; ->ComponentDefinition : Symbol(ComponentDefinition, Decl(neverReturningFunctions1.ts, 193, 27)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 195, 32)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 195, 32)) +>ComponentDefinition : Symbol(ComponentDefinition, Decl(neverReturningFunctions1.ts, 200, 27)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 202, 32)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 202, 32)) >Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) ->Component : Symbol(Component, Decl(neverReturningFunctions1.ts, 153, 1)) +>Component : Symbol(Component, Decl(neverReturningFunctions1.ts, 160, 1)) >ThisType : Symbol(ThisType, Decl(lib.es5.d.ts, --, --)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 195, 32)) ->Component : Symbol(Component, Decl(neverReturningFunctions1.ts, 153, 1)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 202, 32)) +>Component : Symbol(Component, Decl(neverReturningFunctions1.ts, 160, 1)) const Component = registerComponent('test-component', { ->Component : Symbol(Component, Decl(neverReturningFunctions1.ts, 153, 1), Decl(neverReturningFunctions1.ts, 197, 5)) ->registerComponent : Symbol(registerComponent, Decl(neverReturningFunctions1.ts, 188, 1)) +>Component : Symbol(Component, Decl(neverReturningFunctions1.ts, 160, 1), Decl(neverReturningFunctions1.ts, 204, 5)) +>registerComponent : Symbol(registerComponent, Decl(neverReturningFunctions1.ts, 195, 1)) schema: { ->schema : Symbol(schema, Decl(neverReturningFunctions1.ts, 197, 55)) +>schema : Symbol(schema, Decl(neverReturningFunctions1.ts, 204, 55)) myProperty: { ->myProperty : Symbol(myProperty, Decl(neverReturningFunctions1.ts, 198, 10)) +>myProperty : Symbol(myProperty, Decl(neverReturningFunctions1.ts, 205, 10)) default: [], ->default : Symbol(default, Decl(neverReturningFunctions1.ts, 199, 15)) +>default : Symbol(default, Decl(neverReturningFunctions1.ts, 206, 15)) parse() { ->parse : Symbol(parse, Decl(neverReturningFunctions1.ts, 200, 15)) +>parse : Symbol(parse, Decl(neverReturningFunctions1.ts, 207, 15)) return [true]; } }, string: { type: 'string' }, ->string : Symbol(string, Decl(neverReturningFunctions1.ts, 204, 4)) ->type : Symbol(type, Decl(neverReturningFunctions1.ts, 205, 11)) +>string : Symbol(string, Decl(neverReturningFunctions1.ts, 211, 4)) +>type : Symbol(type, Decl(neverReturningFunctions1.ts, 212, 11)) num: 0 ->num : Symbol(num, Decl(neverReturningFunctions1.ts, 205, 29)) +>num : Symbol(num, Decl(neverReturningFunctions1.ts, 212, 29)) }, init() { ->init : Symbol(init, Decl(neverReturningFunctions1.ts, 207, 3)) +>init : Symbol(init, Decl(neverReturningFunctions1.ts, 214, 3)) this.data.num = 0; ->this.data : Symbol(Component.data, Decl(neverReturningFunctions1.ts, 158, 19)) ->data : Symbol(Component.data, Decl(neverReturningFunctions1.ts, 158, 19)) +>this.data : Symbol(Component.data, Decl(neverReturningFunctions1.ts, 165, 19)) +>data : Symbol(Component.data, Decl(neverReturningFunctions1.ts, 165, 19)) this.el.setAttribute('custom-attribute', 'custom-value'); ->this.el : Symbol(Component.el, Decl(neverReturningFunctions1.ts, 160, 25)) ->el : Symbol(Component.el, Decl(neverReturningFunctions1.ts, 160, 25)) +>this.el : Symbol(Component.el, Decl(neverReturningFunctions1.ts, 167, 25)) +>el : Symbol(Component.el, Decl(neverReturningFunctions1.ts, 167, 25)) }, update() {}, ->update : Symbol(update, Decl(neverReturningFunctions1.ts, 211, 3)) +>update : Symbol(update, Decl(neverReturningFunctions1.ts, 218, 3)) tick() {}, ->tick : Symbol(tick, Decl(neverReturningFunctions1.ts, 212, 13)) +>tick : Symbol(tick, Decl(neverReturningFunctions1.ts, 219, 13)) remove() {}, ->remove : Symbol(remove, Decl(neverReturningFunctions1.ts, 213, 11)) +>remove : Symbol(remove, Decl(neverReturningFunctions1.ts, 220, 11)) pause() {}, ->pause : Symbol(pause, Decl(neverReturningFunctions1.ts, 214, 13)) +>pause : Symbol(pause, Decl(neverReturningFunctions1.ts, 221, 13)) play() {}, ->play : Symbol(play, Decl(neverReturningFunctions1.ts, 215, 12)) +>play : Symbol(play, Decl(neverReturningFunctions1.ts, 222, 12)) multiply(f: number) { ->multiply : Symbol(multiply, Decl(neverReturningFunctions1.ts, 216, 11)) ->f : Symbol(f, Decl(neverReturningFunctions1.ts, 218, 10)) +>multiply : Symbol(multiply, Decl(neverReturningFunctions1.ts, 223, 11)) +>f : Symbol(f, Decl(neverReturningFunctions1.ts, 225, 10)) // Reference to system because both were registered with the same name. return f * this.data.num * this.system!.data.counter; ->f : Symbol(f, Decl(neverReturningFunctions1.ts, 218, 10)) ->this.data : Symbol(Component.data, Decl(neverReturningFunctions1.ts, 158, 19)) ->data : Symbol(Component.data, Decl(neverReturningFunctions1.ts, 158, 19)) ->this.system : Symbol(Component.system, Decl(neverReturningFunctions1.ts, 165, 17)) ->system : Symbol(Component.system, Decl(neverReturningFunctions1.ts, 165, 17)) +>f : Symbol(f, Decl(neverReturningFunctions1.ts, 225, 10)) +>this.data : Symbol(Component.data, Decl(neverReturningFunctions1.ts, 165, 19)) +>data : Symbol(Component.data, Decl(neverReturningFunctions1.ts, 165, 19)) +>this.system : Symbol(Component.system, Decl(neverReturningFunctions1.ts, 172, 17)) +>system : Symbol(Component.system, Decl(neverReturningFunctions1.ts, 172, 17)) } }); diff --git a/tests/baselines/reference/neverReturningFunctions1.types b/tests/baselines/reference/neverReturningFunctions1.types index ed49d1841b878..9089630ab9a46 100644 --- a/tests/baselines/reference/neverReturningFunctions1.types +++ b/tests/baselines/reference/neverReturningFunctions1.types @@ -437,6 +437,31 @@ function f42(x: number) { >x : number } +function f43() { +>f43 : () => void + + const fail = (): never => { throw new Error(); }; +>fail : () => never +>(): never => { throw new Error(); } : () => never +>new Error() : Error +>Error : ErrorConstructor + + const f = [fail]; +>f : (() => never)[] +>[fail] : (() => never)[] +>fail : () => never + + fail(); // Error +>fail() : never +>fail : () => never + + f[0](); // Error +>f[0]() : never +>f[0] : () => never +>f : (() => never)[] +>0 : 0 +} + // Repro from #33582 export interface Component { From a13f8621c223814f720dbe2de24bf92a57bda54a Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 26 Sep 2019 17:24:14 -0700 Subject: [PATCH 4/9] Handle alias symbols in getTypeOfDottedName --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1a20173f4c261..9546463c00967 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17205,7 +17205,7 @@ namespace ts { if (!(node.flags & NodeFlags.InWithStatement)) { switch (node.kind) { case SyntaxKind.Identifier: - const symbol = getResolvedSymbol(node); + const symbol = getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(node)); return getExplicitTypeOfSymbol(symbol.flags & SymbolFlags.Alias ? resolveAlias(symbol) : symbol); case SyntaxKind.ThisKeyword: return getExplicitThisType(node); From 4648d6aeb24aad5d10713c4a93d5fea4050d7c7d Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 27 Sep 2019 15:05:13 -0700 Subject: [PATCH 5/9] Revise error messages + related spans + no errors on never-returning functions --- src/compiler/checker.ts | 35 +++++++++++++++++----------- src/compiler/diagnosticMessages.json | 4 ++-- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9546463c00967..3bc8d88f4fa2f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17191,30 +17191,38 @@ namespace ts { getEffectiveTypeAnnotationNode(declaration as VariableDeclaration | ParameterDeclaration | PropertyDeclaration | PropertySignature)); } - function getExplicitTypeOfSymbol(symbol: Symbol) { - return symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.ValueModule) || - symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property) && isDeclarationWithExplicitTypeAnnotation(symbol.valueDeclaration) ? - getTypeOfSymbol(symbol) : undefined; + function getExplicitTypeOfSymbol(symbol: Symbol, diagnostic?: Diagnostic) { + if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.ValueModule)) { + return getTypeOfSymbol(symbol); + } + if (symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property)) { + if (isDeclarationWithExplicitTypeAnnotation(symbol.valueDeclaration)) { + return getTypeOfSymbol(symbol); + } + if (diagnostic && symbol.valueDeclaration) { + addRelatedInfo(diagnostic, createDiagnosticForNode(symbol.valueDeclaration, Diagnostics._0_is_declared_here, symbolToString(symbol))); + } + } } // We require the dotted function name in an assertion expression to be comprised of identifiers // that reference function, method, class or value module symbols; or variable, property or // parameter symbols with declarations that have explicit type annotations. Such references are // resolvable with no possibility of triggering circularities in control flow analysis. - function getTypeOfDottedName(node: Expression): Type | undefined { + function getTypeOfDottedName(node: Expression, diagnostic: Diagnostic | undefined): Type | undefined { if (!(node.flags & NodeFlags.InWithStatement)) { switch (node.kind) { case SyntaxKind.Identifier: const symbol = getExportSymbolOfValueSymbolIfExported(getResolvedSymbol(node)); - return getExplicitTypeOfSymbol(symbol.flags & SymbolFlags.Alias ? resolveAlias(symbol) : symbol); + return getExplicitTypeOfSymbol(symbol.flags & SymbolFlags.Alias ? resolveAlias(symbol) : symbol, diagnostic); case SyntaxKind.ThisKeyword: return getExplicitThisType(node); case SyntaxKind.PropertyAccessExpression: - const type = getTypeOfDottedName((node).expression); + const type = getTypeOfDottedName((node).expression, diagnostic); const prop = type && getPropertyOfType(type, (node).name.escapedText); - return prop && getExplicitTypeOfSymbol(prop); + return prop && getExplicitTypeOfSymbol(prop, diagnostic); case SyntaxKind.ParenthesizedExpression: - return getTypeOfDottedName((node).expression); + return getTypeOfDottedName((node).expression, diagnostic); } } } @@ -17227,7 +17235,7 @@ namespace ts { // expressions are potential type predicate function calls. In order to avoid triggering // circularities in control flow analysis, we use getTypeOfDottedName when resolving the call // target expression of an assertion. - const funcType = node.parent.kind === SyntaxKind.ExpressionStatement ? getTypeOfDottedName(node.expression) : + const funcType = node.parent.kind === SyntaxKind.ExpressionStatement ? getTypeOfDottedName(node.expression, /*diagnostic*/ undefined) : node.expression.kind !== SyntaxKind.SuperKeyword ? checkNonNullExpression(node.expression) : undefined; const signatures = getSignaturesOfType(funcType && getApparentType(funcType) || unknownType, SignatureKind.Call); @@ -23417,12 +23425,13 @@ namespace ts { return getESSymbolLikeTypeForNode(walkUpParenthesizedExpressions(node.parent)); } if (node.kind === SyntaxKind.CallExpression && node.parent.kind === SyntaxKind.ExpressionStatement && - returnType.flags & (TypeFlags.Void | TypeFlags.Never) && hasTypePredicateOrNeverReturnType(signature)) { + returnType.flags & TypeFlags.Void && getTypePredicateOfSignature(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); + error(node.expression, Diagnostics.Assertions_require_the_call_target_to_be_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); + const diagnostic = error(node.expression, Diagnostics.Assertions_require_every_name_in_the_call_target_to_be_declared_with_an_explicit_type_annotation); + getTypeOfDottedName(node.expression, diagnostic); } } let jsAssignmentType: Type | undefined; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 056b02f7cb3ce..ff8df4b5b9506 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2726,11 +2726,11 @@ "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.": { + "Assertions require every name in the call target to be 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.": { + "Assertions require the call target to be an identifier or qualified-name.": { "category": "Error", "code": 2776 }, From 02395a9b271c3e5688d67dab74c91211a119ceb1 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 27 Sep 2019 15:17:49 -0700 Subject: [PATCH 6/9] Fix error message --- src/compiler/diagnosticMessages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index ff8df4b5b9506..c0fd0632862fd 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2730,7 +2730,7 @@ "category": "Error", "code": 2775 }, - "Assertions require the call target to be an identifier or qualified-name.": { + "Assertions require the call target to be an identifier or qualified name.": { "category": "Error", "code": 2776 }, From 56e0c6b16ed4c24661deadda890220c012e7003f Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 27 Sep 2019 15:20:03 -0700 Subject: [PATCH 7/9] Accept new baselines --- .../reference/assertionTypePredicates1.errors.txt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/baselines/reference/assertionTypePredicates1.errors.txt b/tests/baselines/reference/assertionTypePredicates1.errors.txt index 68253ff06b65c..2fe95b995487f 100644 --- a/tests/baselines/reference/assertionTypePredicates1.errors.txt +++ b/tests/baselines/reference/assertionTypePredicates1.errors.txt @@ -5,9 +5,9 @@ tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(121,15): error T tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(122,15): error TS1228: A type predicate is only allowed in return type position for functions and methods. tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(123,15): error TS1228: A type predicate is only allowed in return type position for functions and methods. tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(124,15): error TS1228: A type predicate is only allowed in return type position for functions and methods. -tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(129,5): error TS2775: 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. -tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(131,5): error TS2776: Control flow effects of calls to assertion and never-returning functions are reflected only when the function expression is an identifier or qualified-name. -tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(133,5): error TS2775: 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. +tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(129,5): error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation. +tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(131,5): error TS2776: Assertions require the call target to be an identifier or qualified name. +tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(133,5): error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation. ==== tests/cases/conformance/controlFlow/assertionTypePredicates1.ts (10 errors) ==== @@ -155,15 +155,17 @@ tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(133,5): error TS const assert = (value: unknown): asserts value => {} assert(typeof x === "string"); // Error ~~~~~~ -!!! error TS2775: 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. +!!! error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation. +!!! related TS2728 tests/cases/conformance/controlFlow/assertionTypePredicates1.ts:128:11: 'assert' is declared here. const a = [assert]; a[0](typeof x === "string"); // Error ~~~~ -!!! error TS2776: Control flow effects of calls to assertion and never-returning functions are reflected only when the function expression is an identifier or qualified-name. +!!! error TS2776: Assertions require the call target to be an identifier or qualified name. const t1 = new Test(); t1.assert(typeof x === "string"); // Error ~~~~~~~~~ -!!! error TS2775: 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. +!!! error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation. +!!! related TS2728 tests/cases/conformance/controlFlow/assertionTypePredicates1.ts:132:11: 't1' is declared here. const t2: Test = new Test(); t2.assert(typeof x === "string"); } From 34f6e681c492650d36438cf23838a4c33d496a11 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 27 Sep 2019 15:23:49 -0700 Subject: [PATCH 8/9] Update tests --- .../conformance/controlFlow/neverReturningFunctions1.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/cases/conformance/controlFlow/neverReturningFunctions1.ts b/tests/cases/conformance/controlFlow/neverReturningFunctions1.ts index e1e0d43de4bf6..3a4e2899ca26f 100644 --- a/tests/cases/conformance/controlFlow/neverReturningFunctions1.ts +++ b/tests/cases/conformance/controlFlow/neverReturningFunctions1.ts @@ -160,8 +160,9 @@ function f42(x: number) { function f43() { const fail = (): never => { throw new Error(); }; const f = [fail]; - fail(); // Error - f[0](); // Error + fail(); // No effect (missing type annotation) + f[0](); // No effect (not a dotted name) + f; } // Repro from #33582 From e5af71e3cd00c9803b07767e65d4afdd8419e661 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 27 Sep 2019 15:23:57 -0700 Subject: [PATCH 9/9] Accept new baselines --- .../neverReturningFunctions1.errors.txt | 13 +- .../reference/neverReturningFunctions1.js | 10 +- .../neverReturningFunctions1.symbols | 169 +++++++++--------- .../reference/neverReturningFunctions1.types | 7 +- 4 files changed, 101 insertions(+), 98 deletions(-) diff --git a/tests/baselines/reference/neverReturningFunctions1.errors.txt b/tests/baselines/reference/neverReturningFunctions1.errors.txt index 5c6ba45ea4ab8..73713465e7d29 100644 --- a/tests/baselines/reference/neverReturningFunctions1.errors.txt +++ b/tests/baselines/reference/neverReturningFunctions1.errors.txt @@ -21,11 +21,9 @@ tests/cases/conformance/controlFlow/neverReturningFunctions1.ts(139,9): error TS tests/cases/conformance/controlFlow/neverReturningFunctions1.ts(141,5): error TS7027: Unreachable code detected. tests/cases/conformance/controlFlow/neverReturningFunctions1.ts(148,9): error TS7027: Unreachable code detected. tests/cases/conformance/controlFlow/neverReturningFunctions1.ts(153,5): error TS7027: Unreachable code detected. -tests/cases/conformance/controlFlow/neverReturningFunctions1.ts(159,5): error TS2775: 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. -tests/cases/conformance/controlFlow/neverReturningFunctions1.ts(160,5): error TS2776: Control flow effects of calls to assertion and never-returning functions are reflected only when the function expression is an identifier or qualified-name. -==== tests/cases/conformance/controlFlow/neverReturningFunctions1.ts (25 errors) ==== +==== tests/cases/conformance/controlFlow/neverReturningFunctions1.ts (23 errors) ==== function fail(message?: string): never { throw new Error(message); } @@ -230,12 +228,9 @@ tests/cases/conformance/controlFlow/neverReturningFunctions1.ts(160,5): error TS function f43() { const fail = (): never => { throw new Error(); }; const f = [fail]; - fail(); // Error - ~~~~ -!!! error TS2775: 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. - f[0](); // Error - ~~~~ -!!! error TS2776: Control flow effects of calls to assertion and never-returning functions are reflected only when the function expression is an identifier or qualified-name. + fail(); // No effect (missing type annotation) + f[0](); // No effect (not a dotted name) + f; } // Repro from #33582 diff --git a/tests/baselines/reference/neverReturningFunctions1.js b/tests/baselines/reference/neverReturningFunctions1.js index dc79d7733dff1..e6f13468cc60e 100644 --- a/tests/baselines/reference/neverReturningFunctions1.js +++ b/tests/baselines/reference/neverReturningFunctions1.js @@ -157,8 +157,9 @@ function f42(x: number) { function f43() { const fail = (): never => { throw new Error(); }; const f = [fail]; - fail(); // Error - f[0](); // Error + fail(); // No effect (missing type annotation) + f[0](); // No effect (not a dotted name) + f; } // Repro from #33582 @@ -385,8 +386,9 @@ function f42(x) { function f43() { var fail = function () { throw new Error(); }; var f = [fail]; - fail(); // Error - f[0](); // Error + fail(); // No effect (missing type annotation) + f[0](); // No effect (not a dotted name) + f; } var Component = registerComponent('test-component', { schema: { diff --git a/tests/baselines/reference/neverReturningFunctions1.symbols b/tests/baselines/reference/neverReturningFunctions1.symbols index 3dff8bef7e32b..b73830503bf9c 100644 --- a/tests/baselines/reference/neverReturningFunctions1.symbols +++ b/tests/baselines/reference/neverReturningFunctions1.symbols @@ -396,203 +396,206 @@ function f43() { >f : Symbol(f, Decl(neverReturningFunctions1.ts, 157, 9)) >fail : Symbol(fail, Decl(neverReturningFunctions1.ts, 156, 9)) - fail(); // Error + fail(); // No effect (missing type annotation) >fail : Symbol(fail, Decl(neverReturningFunctions1.ts, 156, 9)) - f[0](); // Error + f[0](); // No effect (not a dotted name) +>f : Symbol(f, Decl(neverReturningFunctions1.ts, 157, 9)) + + f; >f : Symbol(f, Decl(neverReturningFunctions1.ts, 157, 9)) } // Repro from #33582 export interface Component { ->Component : Symbol(Component, Decl(neverReturningFunctions1.ts, 160, 1)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 164, 27)) +>Component : Symbol(Component, Decl(neverReturningFunctions1.ts, 161, 1)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 165, 27)) attrName?: string; ->attrName : Symbol(Component.attrName, Decl(neverReturningFunctions1.ts, 164, 52)) +>attrName : Symbol(Component.attrName, Decl(neverReturningFunctions1.ts, 165, 52)) data: T; ->data : Symbol(Component.data, Decl(neverReturningFunctions1.ts, 165, 19)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 164, 27)) +>data : Symbol(Component.data, Decl(neverReturningFunctions1.ts, 166, 19)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 165, 27)) dependencies?: string[]; ->dependencies : Symbol(Component.dependencies, Decl(neverReturningFunctions1.ts, 166, 9)) +>dependencies : Symbol(Component.dependencies, Decl(neverReturningFunctions1.ts, 167, 9)) el: any; ->el : Symbol(Component.el, Decl(neverReturningFunctions1.ts, 167, 25)) +>el : Symbol(Component.el, Decl(neverReturningFunctions1.ts, 168, 25)) id: string; ->id : Symbol(Component.id, Decl(neverReturningFunctions1.ts, 168, 9)) +>id : Symbol(Component.id, Decl(neverReturningFunctions1.ts, 169, 9)) multiple?: boolean; ->multiple : Symbol(Component.multiple, Decl(neverReturningFunctions1.ts, 169, 12)) +>multiple : Symbol(Component.multiple, Decl(neverReturningFunctions1.ts, 170, 12)) name: string; ->name : Symbol(Component.name, Decl(neverReturningFunctions1.ts, 170, 20)) +>name : Symbol(Component.name, Decl(neverReturningFunctions1.ts, 171, 20)) schema: unknown; ->schema : Symbol(Component.schema, Decl(neverReturningFunctions1.ts, 171, 14)) +>schema : Symbol(Component.schema, Decl(neverReturningFunctions1.ts, 172, 14)) system: any; ->system : Symbol(Component.system, Decl(neverReturningFunctions1.ts, 172, 17)) +>system : Symbol(Component.system, Decl(neverReturningFunctions1.ts, 173, 17)) init(data?: T): void; ->init : Symbol(Component.init, Decl(neverReturningFunctions1.ts, 173, 13)) ->data : Symbol(data, Decl(neverReturningFunctions1.ts, 175, 6)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 164, 27)) +>init : Symbol(Component.init, Decl(neverReturningFunctions1.ts, 174, 13)) +>data : Symbol(data, Decl(neverReturningFunctions1.ts, 176, 6)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 165, 27)) pause(): void; ->pause : Symbol(Component.pause, Decl(neverReturningFunctions1.ts, 175, 22)) +>pause : Symbol(Component.pause, Decl(neverReturningFunctions1.ts, 176, 22)) play(): void; ->play : Symbol(Component.play, Decl(neverReturningFunctions1.ts, 176, 15)) +>play : Symbol(Component.play, Decl(neverReturningFunctions1.ts, 177, 15)) remove(): void; ->remove : Symbol(Component.remove, Decl(neverReturningFunctions1.ts, 177, 14)) +>remove : Symbol(Component.remove, Decl(neverReturningFunctions1.ts, 178, 14)) tick?(time: number, timeDelta: number): void; ->tick : Symbol(Component.tick, Decl(neverReturningFunctions1.ts, 178, 16)) ->time : Symbol(time, Decl(neverReturningFunctions1.ts, 179, 7)) ->timeDelta : Symbol(timeDelta, Decl(neverReturningFunctions1.ts, 179, 20)) +>tick : Symbol(Component.tick, Decl(neverReturningFunctions1.ts, 179, 16)) +>time : Symbol(time, Decl(neverReturningFunctions1.ts, 180, 7)) +>timeDelta : Symbol(timeDelta, Decl(neverReturningFunctions1.ts, 180, 20)) update(oldData: T): void; ->update : Symbol(Component.update, Decl(neverReturningFunctions1.ts, 179, 46)) ->oldData : Symbol(oldData, Decl(neverReturningFunctions1.ts, 180, 8)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 164, 27)) +>update : Symbol(Component.update, Decl(neverReturningFunctions1.ts, 180, 46)) +>oldData : Symbol(oldData, Decl(neverReturningFunctions1.ts, 181, 8)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 165, 27)) updateSchema?(): void; ->updateSchema : Symbol(Component.updateSchema, Decl(neverReturningFunctions1.ts, 180, 26)) +>updateSchema : Symbol(Component.updateSchema, Decl(neverReturningFunctions1.ts, 181, 26)) extendSchema(update: unknown): void; ->extendSchema : Symbol(Component.extendSchema, Decl(neverReturningFunctions1.ts, 181, 23)) ->update : Symbol(update, Decl(neverReturningFunctions1.ts, 183, 14)) +>extendSchema : Symbol(Component.extendSchema, Decl(neverReturningFunctions1.ts, 182, 23)) +>update : Symbol(update, Decl(neverReturningFunctions1.ts, 184, 14)) flushToDOM(): void; ->flushToDOM : Symbol(Component.flushToDOM, Decl(neverReturningFunctions1.ts, 183, 37)) +>flushToDOM : Symbol(Component.flushToDOM, Decl(neverReturningFunctions1.ts, 184, 37)) } export interface ComponentConstructor { ->ComponentConstructor : Symbol(ComponentConstructor, Decl(neverReturningFunctions1.ts, 185, 1)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 187, 38)) +>ComponentConstructor : Symbol(ComponentConstructor, Decl(neverReturningFunctions1.ts, 186, 1)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 188, 38)) new (el: unknown, attrValue: string, id: string): T & Component; ->el : Symbol(el, Decl(neverReturningFunctions1.ts, 188, 6)) ->attrValue : Symbol(attrValue, Decl(neverReturningFunctions1.ts, 188, 18)) ->id : Symbol(id, Decl(neverReturningFunctions1.ts, 188, 37)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 187, 38)) ->Component : Symbol(Component, Decl(neverReturningFunctions1.ts, 160, 1)) +>el : Symbol(el, Decl(neverReturningFunctions1.ts, 189, 6)) +>attrValue : Symbol(attrValue, Decl(neverReturningFunctions1.ts, 189, 18)) +>id : Symbol(id, Decl(neverReturningFunctions1.ts, 189, 37)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 188, 38)) +>Component : Symbol(Component, Decl(neverReturningFunctions1.ts, 161, 1)) prototype: T & { ->prototype : Symbol(ComponentConstructor.prototype, Decl(neverReturningFunctions1.ts, 188, 65)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 187, 38)) +>prototype : Symbol(ComponentConstructor.prototype, Decl(neverReturningFunctions1.ts, 189, 65)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 188, 38)) name: string; ->name : Symbol(name, Decl(neverReturningFunctions1.ts, 189, 17)) +>name : Symbol(name, Decl(neverReturningFunctions1.ts, 190, 17)) system: unknown; ->system : Symbol(system, Decl(neverReturningFunctions1.ts, 190, 15)) +>system : Symbol(system, Decl(neverReturningFunctions1.ts, 191, 15)) play(): void; ->play : Symbol(play, Decl(neverReturningFunctions1.ts, 191, 18)) +>play : Symbol(play, Decl(neverReturningFunctions1.ts, 192, 18)) pause(): void; ->pause : Symbol(pause, Decl(neverReturningFunctions1.ts, 192, 15)) +>pause : Symbol(pause, Decl(neverReturningFunctions1.ts, 193, 15)) }; } declare function registerComponent( ->registerComponent : Symbol(registerComponent, Decl(neverReturningFunctions1.ts, 195, 1)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 197, 35)) +>registerComponent : Symbol(registerComponent, Decl(neverReturningFunctions1.ts, 196, 1)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 198, 35)) name: string, ->name : Symbol(name, Decl(neverReturningFunctions1.ts, 197, 53)) +>name : Symbol(name, Decl(neverReturningFunctions1.ts, 198, 53)) component: ComponentDefinition ->component : Symbol(component, Decl(neverReturningFunctions1.ts, 198, 17)) ->ComponentDefinition : Symbol(ComponentDefinition, Decl(neverReturningFunctions1.ts, 200, 27)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 197, 35)) +>component : Symbol(component, Decl(neverReturningFunctions1.ts, 199, 17)) +>ComponentDefinition : Symbol(ComponentDefinition, Decl(neverReturningFunctions1.ts, 201, 27)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 198, 35)) ): ComponentConstructor; ->ComponentConstructor : Symbol(ComponentConstructor, Decl(neverReturningFunctions1.ts, 185, 1)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 197, 35)) +>ComponentConstructor : Symbol(ComponentConstructor, Decl(neverReturningFunctions1.ts, 186, 1)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 198, 35)) export type ComponentDefinition = T & Partial & ThisType; ->ComponentDefinition : Symbol(ComponentDefinition, Decl(neverReturningFunctions1.ts, 200, 27)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 202, 32)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 202, 32)) +>ComponentDefinition : Symbol(ComponentDefinition, Decl(neverReturningFunctions1.ts, 201, 27)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 203, 32)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 203, 32)) >Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) ->Component : Symbol(Component, Decl(neverReturningFunctions1.ts, 160, 1)) +>Component : Symbol(Component, Decl(neverReturningFunctions1.ts, 161, 1)) >ThisType : Symbol(ThisType, Decl(lib.es5.d.ts, --, --)) ->T : Symbol(T, Decl(neverReturningFunctions1.ts, 202, 32)) ->Component : Symbol(Component, Decl(neverReturningFunctions1.ts, 160, 1)) +>T : Symbol(T, Decl(neverReturningFunctions1.ts, 203, 32)) +>Component : Symbol(Component, Decl(neverReturningFunctions1.ts, 161, 1)) const Component = registerComponent('test-component', { ->Component : Symbol(Component, Decl(neverReturningFunctions1.ts, 160, 1), Decl(neverReturningFunctions1.ts, 204, 5)) ->registerComponent : Symbol(registerComponent, Decl(neverReturningFunctions1.ts, 195, 1)) +>Component : Symbol(Component, Decl(neverReturningFunctions1.ts, 161, 1), Decl(neverReturningFunctions1.ts, 205, 5)) +>registerComponent : Symbol(registerComponent, Decl(neverReturningFunctions1.ts, 196, 1)) schema: { ->schema : Symbol(schema, Decl(neverReturningFunctions1.ts, 204, 55)) +>schema : Symbol(schema, Decl(neverReturningFunctions1.ts, 205, 55)) myProperty: { ->myProperty : Symbol(myProperty, Decl(neverReturningFunctions1.ts, 205, 10)) +>myProperty : Symbol(myProperty, Decl(neverReturningFunctions1.ts, 206, 10)) default: [], ->default : Symbol(default, Decl(neverReturningFunctions1.ts, 206, 15)) +>default : Symbol(default, Decl(neverReturningFunctions1.ts, 207, 15)) parse() { ->parse : Symbol(parse, Decl(neverReturningFunctions1.ts, 207, 15)) +>parse : Symbol(parse, Decl(neverReturningFunctions1.ts, 208, 15)) return [true]; } }, string: { type: 'string' }, ->string : Symbol(string, Decl(neverReturningFunctions1.ts, 211, 4)) ->type : Symbol(type, Decl(neverReturningFunctions1.ts, 212, 11)) +>string : Symbol(string, Decl(neverReturningFunctions1.ts, 212, 4)) +>type : Symbol(type, Decl(neverReturningFunctions1.ts, 213, 11)) num: 0 ->num : Symbol(num, Decl(neverReturningFunctions1.ts, 212, 29)) +>num : Symbol(num, Decl(neverReturningFunctions1.ts, 213, 29)) }, init() { ->init : Symbol(init, Decl(neverReturningFunctions1.ts, 214, 3)) +>init : Symbol(init, Decl(neverReturningFunctions1.ts, 215, 3)) this.data.num = 0; ->this.data : Symbol(Component.data, Decl(neverReturningFunctions1.ts, 165, 19)) ->data : Symbol(Component.data, Decl(neverReturningFunctions1.ts, 165, 19)) +>this.data : Symbol(Component.data, Decl(neverReturningFunctions1.ts, 166, 19)) +>data : Symbol(Component.data, Decl(neverReturningFunctions1.ts, 166, 19)) this.el.setAttribute('custom-attribute', 'custom-value'); ->this.el : Symbol(Component.el, Decl(neverReturningFunctions1.ts, 167, 25)) ->el : Symbol(Component.el, Decl(neverReturningFunctions1.ts, 167, 25)) +>this.el : Symbol(Component.el, Decl(neverReturningFunctions1.ts, 168, 25)) +>el : Symbol(Component.el, Decl(neverReturningFunctions1.ts, 168, 25)) }, update() {}, ->update : Symbol(update, Decl(neverReturningFunctions1.ts, 218, 3)) +>update : Symbol(update, Decl(neverReturningFunctions1.ts, 219, 3)) tick() {}, ->tick : Symbol(tick, Decl(neverReturningFunctions1.ts, 219, 13)) +>tick : Symbol(tick, Decl(neverReturningFunctions1.ts, 220, 13)) remove() {}, ->remove : Symbol(remove, Decl(neverReturningFunctions1.ts, 220, 11)) +>remove : Symbol(remove, Decl(neverReturningFunctions1.ts, 221, 11)) pause() {}, ->pause : Symbol(pause, Decl(neverReturningFunctions1.ts, 221, 13)) +>pause : Symbol(pause, Decl(neverReturningFunctions1.ts, 222, 13)) play() {}, ->play : Symbol(play, Decl(neverReturningFunctions1.ts, 222, 12)) +>play : Symbol(play, Decl(neverReturningFunctions1.ts, 223, 12)) multiply(f: number) { ->multiply : Symbol(multiply, Decl(neverReturningFunctions1.ts, 223, 11)) ->f : Symbol(f, Decl(neverReturningFunctions1.ts, 225, 10)) +>multiply : Symbol(multiply, Decl(neverReturningFunctions1.ts, 224, 11)) +>f : Symbol(f, Decl(neverReturningFunctions1.ts, 226, 10)) // Reference to system because both were registered with the same name. return f * this.data.num * this.system!.data.counter; ->f : Symbol(f, Decl(neverReturningFunctions1.ts, 225, 10)) ->this.data : Symbol(Component.data, Decl(neverReturningFunctions1.ts, 165, 19)) ->data : Symbol(Component.data, Decl(neverReturningFunctions1.ts, 165, 19)) ->this.system : Symbol(Component.system, Decl(neverReturningFunctions1.ts, 172, 17)) ->system : Symbol(Component.system, Decl(neverReturningFunctions1.ts, 172, 17)) +>f : Symbol(f, Decl(neverReturningFunctions1.ts, 226, 10)) +>this.data : Symbol(Component.data, Decl(neverReturningFunctions1.ts, 166, 19)) +>data : Symbol(Component.data, Decl(neverReturningFunctions1.ts, 166, 19)) +>this.system : Symbol(Component.system, Decl(neverReturningFunctions1.ts, 173, 17)) +>system : Symbol(Component.system, Decl(neverReturningFunctions1.ts, 173, 17)) } }); diff --git a/tests/baselines/reference/neverReturningFunctions1.types b/tests/baselines/reference/neverReturningFunctions1.types index 9089630ab9a46..d92d2472b4d05 100644 --- a/tests/baselines/reference/neverReturningFunctions1.types +++ b/tests/baselines/reference/neverReturningFunctions1.types @@ -451,15 +451,18 @@ function f43() { >[fail] : (() => never)[] >fail : () => never - fail(); // Error + fail(); // No effect (missing type annotation) >fail() : never >fail : () => never - f[0](); // Error + f[0](); // No effect (not a dotted name) >f[0]() : never >f[0] : () => never >f : (() => never)[] >0 : 0 + + f; +>f : (() => never)[] } // Repro from #33582