From da6123103957ddfec89cfab44b537eb89e3f030b Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 22 Jan 2020 11:21:11 -0800 Subject: [PATCH] Include super.XXX(...) assertion method calls in CFA (#36293) * Support super.XXX in assertions * Add tests --- src/compiler/checker.ts | 2 + src/compiler/utilities.ts | 2 +- .../assertionTypePredicates1.errors.txt | 40 +++++--- .../reference/assertionTypePredicates1.js | 30 ++++++ .../assertionTypePredicates1.symbols | 99 ++++++++++++------- .../reference/assertionTypePredicates1.types | 39 ++++++++ .../neverReturningFunctions1.errors.txt | 17 ++++ .../reference/neverReturningFunctions1.js | 52 ++++++++++ .../neverReturningFunctions1.symbols | 36 +++++++ .../reference/neverReturningFunctions1.types | 39 ++++++++ .../controlFlow/assertionTypePredicates1.ts | 11 +++ .../controlFlow/neverReturningFunctions1.ts | 17 ++++ 12 files changed, 337 insertions(+), 47 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 92ba8cb9fb5..9a5a7d5b36e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -19075,6 +19075,8 @@ namespace ts { return getExplicitTypeOfSymbol(symbol.flags & SymbolFlags.Alias ? resolveAlias(symbol) : symbol, diagnostic); case SyntaxKind.ThisKeyword: return getExplicitThisType(node); + case SyntaxKind.SuperKeyword: + return checkSuperExpression(node); case SyntaxKind.PropertyAccessExpression: const type = getTypeOfDottedName((node).expression, diagnostic); const prop = type && getPropertyOfType(type, (node).name.escapedText); diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 76394eeef53..9d57cd8c078 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -4278,7 +4278,7 @@ namespace ts { } export function isDottedName(node: Expression): boolean { - return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisKeyword || + return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisKeyword || node.kind === SyntaxKind.SuperKeyword || node.kind === SyntaxKind.PropertyAccessExpression && isDottedName((node).expression) || node.kind === SyntaxKind.ParenthesizedExpression && isDottedName((node).expression); } diff --git a/tests/baselines/reference/assertionTypePredicates1.errors.txt b/tests/baselines/reference/assertionTypePredicates1.errors.txt index 9b23370a4c9..1ce19562cff 100644 --- a/tests/baselines/reference/assertionTypePredicates1.errors.txt +++ b/tests/baselines/reference/assertionTypePredicates1.errors.txt @@ -2,19 +2,20 @@ tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(39,9): error TS7 tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(43,9): error TS7027: Unreachable code detected. tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(87,9): error TS7027: Unreachable code detected. tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(122,9): error TS7027: Unreachable code detected. -tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(132,37): error TS1228: A type predicate is only allowed in return type position for functions and methods. -tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(133,37): error TS1228: A type predicate is only allowed in return type position for functions and methods. -tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(134,37): error TS1228: A type predicate is only allowed in return type position for functions and methods. -tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(137,15): error TS1228: A type predicate is only allowed in return type position for functions and methods. -tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(138,15): error TS1228: A type predicate is only allowed in return type position for functions and methods. -tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(139,15): error TS1228: A type predicate is only allowed in return type position for functions and methods. -tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(140,15): error TS1228: A type predicate is only allowed in return type position for functions and methods. -tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(145,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(147,5): error TS2776: Assertions require the call target to be an identifier or qualified name. -tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(149,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(137,9): error TS7027: Unreachable code detected. +tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(143,37): error TS1228: A type predicate is only allowed in return type position for functions and methods. +tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(144,37): error TS1228: A type predicate is only allowed in return type position for functions and methods. +tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(145,37): error TS1228: A type predicate is only allowed in return type position for functions and methods. +tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(148,15): error TS1228: A type predicate is only allowed in return type position for functions and methods. +tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(149,15): error TS1228: A type predicate is only allowed in return type position for functions and methods. +tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(150,15): error TS1228: A type predicate is only allowed in return type position for functions and methods. +tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(151,15): error TS1228: A type predicate is only allowed in return type position for functions and methods. +tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(156,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(158,5): error TS2776: Assertions require the call target to be an identifier or qualified name. +tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(160,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 (14 errors) ==== +==== tests/cases/conformance/controlFlow/assertionTypePredicates1.ts (15 errors) ==== declare function isString(value: unknown): value is string; declare function isArrayOfStrings(value: unknown): value is string[]; @@ -152,6 +153,19 @@ tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(149,5): error TS z = 0; } + class Derived extends Test { + foo(x: unknown) { + super.assert(typeof x === "string"); + x.length; + } + baz(x: number) { + super.assert(false); + x; // Unreachable + ~~ +!!! error TS7027: Unreachable code detected. + } + } + // Invalid constructs declare let Q1: new (x: unknown) => x is string; @@ -184,7 +198,7 @@ tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(149,5): error TS assert(typeof x === "string"); // Error ~~~~~~ !!! error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation. -!!! related TS2782 tests/cases/conformance/controlFlow/assertionTypePredicates1.ts:144:11: 'assert' needs an explicit type annotation. +!!! related TS2782 tests/cases/conformance/controlFlow/assertionTypePredicates1.ts:155:11: 'assert' needs an explicit type annotation. const a = [assert]; a[0](typeof x === "string"); // Error ~~~~ @@ -193,7 +207,7 @@ tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(149,5): error TS t1.assert(typeof x === "string"); // Error ~~~~~~~~~ !!! error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation. -!!! related TS2782 tests/cases/conformance/controlFlow/assertionTypePredicates1.ts:148:11: 't1' needs an explicit type annotation. +!!! related TS2782 tests/cases/conformance/controlFlow/assertionTypePredicates1.ts:159:11: 't1' needs an explicit type annotation. const t2: Test = new Test(); t2.assert(typeof x === "string"); } diff --git a/tests/baselines/reference/assertionTypePredicates1.js b/tests/baselines/reference/assertionTypePredicates1.js index 8077e87a797..46e88e61ad0 100644 --- a/tests/baselines/reference/assertionTypePredicates1.js +++ b/tests/baselines/reference/assertionTypePredicates1.js @@ -128,6 +128,17 @@ class Test2 extends Test { z = 0; } +class Derived extends Test { + foo(x: unknown) { + super.assert(typeof x === "string"); + x.length; + } + baz(x: number) { + super.assert(false); + x; // Unreachable + } +} + // Invalid constructs declare let Q1: new (x: unknown) => x is string; @@ -293,6 +304,21 @@ var Test2 = /** @class */ (function (_super) { } return Test2; }(Test)); +var Derived = /** @class */ (function (_super) { + __extends(Derived, _super); + function Derived() { + return _super !== null && _super.apply(this, arguments) || this; + } + Derived.prototype.foo = function (x) { + _super.prototype.assert.call(this, typeof x === "string"); + x.length; + }; + Derived.prototype.baz = function (x) { + _super.prototype.assert.call(this, false); + x; // Unreachable + }; + return Derived; +}(Test)); function f20(x) { var assert = function (value) { }; assert(typeof x === "string"); // Error @@ -332,6 +358,10 @@ declare class Test { declare class Test2 extends Test { z: number; } +declare class Derived extends Test { + foo(x: unknown): void; + baz(x: number): void; +} declare let Q1: new (x: unknown) => x is string; declare let Q2: new (x: boolean) => asserts x; declare let Q3: new (x: unknown) => asserts x is string; diff --git a/tests/baselines/reference/assertionTypePredicates1.symbols b/tests/baselines/reference/assertionTypePredicates1.symbols index 758d5eddfe9..90c42678d1f 100644 --- a/tests/baselines/reference/assertionTypePredicates1.symbols +++ b/tests/baselines/reference/assertionTypePredicates1.symbols @@ -359,81 +359,114 @@ class Test2 extends Test { >z : Symbol(Test2.z, Decl(assertionTypePredicates1.ts, 125, 26)) } +class Derived extends Test { +>Derived : Symbol(Derived, Decl(assertionTypePredicates1.ts, 127, 1)) +>Test : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1)) + + foo(x: unknown) { +>foo : Symbol(Derived.foo, Decl(assertionTypePredicates1.ts, 129, 28)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 130, 8)) + + super.assert(typeof x === "string"); +>super.assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12)) +>super : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1)) +>assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 130, 8)) + + x.length; +>x.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 130, 8)) +>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) + } + baz(x: number) { +>baz : Symbol(Derived.baz, Decl(assertionTypePredicates1.ts, 133, 5)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 134, 8)) + + super.assert(false); +>super.assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12)) +>super : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1)) +>assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12)) + + x; // Unreachable +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 134, 8)) + } +} + // Invalid constructs declare let Q1: new (x: unknown) => x is string; ->Q1 : Symbol(Q1, Decl(assertionTypePredicates1.ts, 131, 11)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 131, 21)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 131, 21)) +>Q1 : Symbol(Q1, Decl(assertionTypePredicates1.ts, 142, 11)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 142, 21)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 142, 21)) declare let Q2: new (x: boolean) => asserts x; ->Q2 : Symbol(Q2, Decl(assertionTypePredicates1.ts, 132, 11)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 132, 21)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 132, 21)) +>Q2 : Symbol(Q2, Decl(assertionTypePredicates1.ts, 143, 11)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 143, 21)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 143, 21)) declare let Q3: new (x: unknown) => asserts x is string; ->Q3 : Symbol(Q3, Decl(assertionTypePredicates1.ts, 133, 11)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 133, 21)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 133, 21)) +>Q3 : Symbol(Q3, Decl(assertionTypePredicates1.ts, 144, 11)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 144, 21)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 144, 21)) declare class Wat { ->Wat : Symbol(Wat, Decl(assertionTypePredicates1.ts, 133, 56)) +>Wat : Symbol(Wat, Decl(assertionTypePredicates1.ts, 144, 56)) get p1(): this is string; ->p1 : Symbol(Wat.p1, Decl(assertionTypePredicates1.ts, 135, 19), Decl(assertionTypePredicates1.ts, 136, 29)) +>p1 : Symbol(Wat.p1, Decl(assertionTypePredicates1.ts, 146, 19), Decl(assertionTypePredicates1.ts, 147, 29)) set p1(x: this is string); ->p1 : Symbol(Wat.p1, Decl(assertionTypePredicates1.ts, 135, 19), Decl(assertionTypePredicates1.ts, 136, 29)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 137, 11)) +>p1 : Symbol(Wat.p1, Decl(assertionTypePredicates1.ts, 146, 19), Decl(assertionTypePredicates1.ts, 147, 29)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 148, 11)) get p2(): asserts this is string; ->p2 : Symbol(Wat.p2, Decl(assertionTypePredicates1.ts, 137, 30), Decl(assertionTypePredicates1.ts, 138, 37)) +>p2 : Symbol(Wat.p2, Decl(assertionTypePredicates1.ts, 148, 30), Decl(assertionTypePredicates1.ts, 149, 37)) set p2(x: asserts this is string); ->p2 : Symbol(Wat.p2, Decl(assertionTypePredicates1.ts, 137, 30), Decl(assertionTypePredicates1.ts, 138, 37)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 139, 11)) +>p2 : Symbol(Wat.p2, Decl(assertionTypePredicates1.ts, 148, 30), Decl(assertionTypePredicates1.ts, 149, 37)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 150, 11)) } function f20(x: unknown) { ->f20 : Symbol(f20, Decl(assertionTypePredicates1.ts, 140, 1)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 142, 13)) +>f20 : Symbol(f20, Decl(assertionTypePredicates1.ts, 151, 1)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 153, 13)) const assert = (value: unknown): asserts value => {} ->assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 143, 9)) ->value : Symbol(value, Decl(assertionTypePredicates1.ts, 143, 20)) ->value : Symbol(value, Decl(assertionTypePredicates1.ts, 143, 20)) +>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 154, 9)) +>value : Symbol(value, Decl(assertionTypePredicates1.ts, 154, 20)) +>value : Symbol(value, Decl(assertionTypePredicates1.ts, 154, 20)) assert(typeof x === "string"); // Error ->assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 143, 9)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 142, 13)) +>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 154, 9)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 153, 13)) const a = [assert]; ->a : Symbol(a, Decl(assertionTypePredicates1.ts, 145, 9)) ->assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 143, 9)) +>a : Symbol(a, Decl(assertionTypePredicates1.ts, 156, 9)) +>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 154, 9)) a[0](typeof x === "string"); // Error ->a : Symbol(a, Decl(assertionTypePredicates1.ts, 145, 9)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 142, 13)) +>a : Symbol(a, Decl(assertionTypePredicates1.ts, 156, 9)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 153, 13)) const t1 = new Test(); ->t1 : Symbol(t1, Decl(assertionTypePredicates1.ts, 147, 9)) +>t1 : Symbol(t1, Decl(assertionTypePredicates1.ts, 158, 9)) >Test : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1)) t1.assert(typeof x === "string"); // Error >t1.assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12)) ->t1 : Symbol(t1, Decl(assertionTypePredicates1.ts, 147, 9)) +>t1 : Symbol(t1, Decl(assertionTypePredicates1.ts, 158, 9)) >assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 142, 13)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 153, 13)) const t2: Test = new Test(); ->t2 : Symbol(t2, Decl(assertionTypePredicates1.ts, 149, 9)) +>t2 : Symbol(t2, Decl(assertionTypePredicates1.ts, 160, 9)) >Test : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1)) >Test : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1)) t2.assert(typeof x === "string"); >t2.assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12)) ->t2 : Symbol(t2, Decl(assertionTypePredicates1.ts, 149, 9)) +>t2 : Symbol(t2, Decl(assertionTypePredicates1.ts, 160, 9)) >assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 142, 13)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 153, 13)) } diff --git a/tests/baselines/reference/assertionTypePredicates1.types b/tests/baselines/reference/assertionTypePredicates1.types index ac4100fb449..53c10d9a887 100644 --- a/tests/baselines/reference/assertionTypePredicates1.types +++ b/tests/baselines/reference/assertionTypePredicates1.types @@ -463,6 +463,45 @@ class Test2 extends Test { >0 : 0 } +class Derived extends Test { +>Derived : Derived +>Test : Test + + foo(x: unknown) { +>foo : (x: unknown) => void +>x : unknown + + super.assert(typeof x === "string"); +>super.assert(typeof x === "string") : void +>super.assert : (value: unknown) => asserts value +>super : Test +>assert : (value: unknown) => asserts value +>typeof x === "string" : boolean +>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>x : unknown +>"string" : "string" + + x.length; +>x.length : number +>x : string +>length : number + } + baz(x: number) { +>baz : (x: number) => void +>x : number + + super.assert(false); +>super.assert(false) : void +>super.assert : (value: unknown) => asserts value +>super : Test +>assert : (value: unknown) => asserts value +>false : false + + x; // Unreachable +>x : number + } +} + // Invalid constructs declare let Q1: new (x: unknown) => x is string; diff --git a/tests/baselines/reference/neverReturningFunctions1.errors.txt b/tests/baselines/reference/neverReturningFunctions1.errors.txt index 73713465e7d..f84395e501c 100644 --- a/tests/baselines/reference/neverReturningFunctions1.errors.txt +++ b/tests/baselines/reference/neverReturningFunctions1.errors.txt @@ -301,4 +301,21 @@ tests/cases/conformance/controlFlow/neverReturningFunctions1.ts(153,5): error TS return f * this.data.num * this.system!.data.counter; } }); + + // Repro from #36147 + + class MyThrowable { + throw(): never { + throw new Error(); + } + } + + class SuperThrowable extends MyThrowable { + err(msg: string): never { + super.throw() + } + ok(): never { + this.throw() + } + } \ No newline at end of file diff --git a/tests/baselines/reference/neverReturningFunctions1.js b/tests/baselines/reference/neverReturningFunctions1.js index e6f13468cc6..512c8205ce4 100644 --- a/tests/baselines/reference/neverReturningFunctions1.js +++ b/tests/baselines/reference/neverReturningFunctions1.js @@ -230,10 +230,40 @@ const Component = registerComponent('test-component', { return f * this.data.num * this.system!.data.counter; } }); + +// Repro from #36147 + +class MyThrowable { + throw(): never { + throw new Error(); + } +} + +class SuperThrowable extends MyThrowable { + err(msg: string): never { + super.throw() + } + ok(): never { + this.throw() + } +} //// [neverReturningFunctions1.js] "use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); exports.__esModule = true; function fail(message) { throw new Error(message); @@ -415,6 +445,28 @@ var Component = registerComponent('test-component', { return f * this.data.num * this.system.data.counter; } }); +// Repro from #36147 +var MyThrowable = /** @class */ (function () { + function MyThrowable() { + } + MyThrowable.prototype["throw"] = function () { + throw new Error(); + }; + return MyThrowable; +}()); +var SuperThrowable = /** @class */ (function (_super) { + __extends(SuperThrowable, _super); + function SuperThrowable() { + return _super !== null && _super.apply(this, arguments) || this; + } + SuperThrowable.prototype.err = function (msg) { + _super.prototype["throw"].call(this); + }; + SuperThrowable.prototype.ok = function () { + this["throw"](); + }; + return SuperThrowable; +}(MyThrowable)); //// [neverReturningFunctions1.d.ts] diff --git a/tests/baselines/reference/neverReturningFunctions1.symbols b/tests/baselines/reference/neverReturningFunctions1.symbols index b73830503bf..3ecda28aee1 100644 --- a/tests/baselines/reference/neverReturningFunctions1.symbols +++ b/tests/baselines/reference/neverReturningFunctions1.symbols @@ -599,3 +599,39 @@ const Component = registerComponent('test-component', { } }); +// Repro from #36147 + +class MyThrowable { +>MyThrowable : Symbol(MyThrowable, Decl(neverReturningFunctions1.ts, 230, 3)) + + throw(): never { +>throw : Symbol(MyThrowable.throw, Decl(neverReturningFunctions1.ts, 234, 19)) + + throw new Error(); +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + } +} + +class SuperThrowable extends MyThrowable { +>SuperThrowable : Symbol(SuperThrowable, Decl(neverReturningFunctions1.ts, 238, 1)) +>MyThrowable : Symbol(MyThrowable, Decl(neverReturningFunctions1.ts, 230, 3)) + + err(msg: string): never { +>err : Symbol(SuperThrowable.err, Decl(neverReturningFunctions1.ts, 240, 42)) +>msg : Symbol(msg, Decl(neverReturningFunctions1.ts, 241, 8)) + + super.throw() +>super.throw : Symbol(MyThrowable.throw, Decl(neverReturningFunctions1.ts, 234, 19)) +>super : Symbol(MyThrowable, Decl(neverReturningFunctions1.ts, 230, 3)) +>throw : Symbol(MyThrowable.throw, Decl(neverReturningFunctions1.ts, 234, 19)) + } + ok(): never { +>ok : Symbol(SuperThrowable.ok, Decl(neverReturningFunctions1.ts, 243, 5)) + + this.throw() +>this.throw : Symbol(MyThrowable.throw, Decl(neverReturningFunctions1.ts, 234, 19)) +>this : Symbol(SuperThrowable, Decl(neverReturningFunctions1.ts, 238, 1)) +>throw : Symbol(MyThrowable.throw, Decl(neverReturningFunctions1.ts, 234, 19)) + } +} + diff --git a/tests/baselines/reference/neverReturningFunctions1.types b/tests/baselines/reference/neverReturningFunctions1.types index d92d2472b4d..69250693d87 100644 --- a/tests/baselines/reference/neverReturningFunctions1.types +++ b/tests/baselines/reference/neverReturningFunctions1.types @@ -667,3 +667,42 @@ const Component = registerComponent('test-component', { } }); +// Repro from #36147 + +class MyThrowable { +>MyThrowable : MyThrowable + + throw(): never { +>throw : () => never + + throw new Error(); +>new Error() : Error +>Error : ErrorConstructor + } +} + +class SuperThrowable extends MyThrowable { +>SuperThrowable : SuperThrowable +>MyThrowable : MyThrowable + + err(msg: string): never { +>err : (msg: string) => never +>msg : string + + super.throw() +>super.throw() : never +>super.throw : () => never +>super : MyThrowable +>throw : () => never + } + ok(): never { +>ok : () => never + + this.throw() +>this.throw() : never +>this.throw : () => never +>this : this +>throw : () => never + } +} + diff --git a/tests/cases/conformance/controlFlow/assertionTypePredicates1.ts b/tests/cases/conformance/controlFlow/assertionTypePredicates1.ts index 1b7db7affaa..68300463596 100644 --- a/tests/cases/conformance/controlFlow/assertionTypePredicates1.ts +++ b/tests/cases/conformance/controlFlow/assertionTypePredicates1.ts @@ -131,6 +131,17 @@ class Test2 extends Test { z = 0; } +class Derived extends Test { + foo(x: unknown) { + super.assert(typeof x === "string"); + x.length; + } + baz(x: number) { + super.assert(false); + x; // Unreachable + } +} + // Invalid constructs declare let Q1: new (x: unknown) => x is string; diff --git a/tests/cases/conformance/controlFlow/neverReturningFunctions1.ts b/tests/cases/conformance/controlFlow/neverReturningFunctions1.ts index 3a4e2899ca2..c2b553d21b3 100644 --- a/tests/cases/conformance/controlFlow/neverReturningFunctions1.ts +++ b/tests/cases/conformance/controlFlow/neverReturningFunctions1.ts @@ -233,3 +233,20 @@ const Component = registerComponent('test-component', { return f * this.data.num * this.system!.data.counter; } }); + +// Repro from #36147 + +class MyThrowable { + throw(): never { + throw new Error(); + } +} + +class SuperThrowable extends MyThrowable { + err(msg: string): never { + super.throw() + } + ok(): never { + this.throw() + } +}