diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 12d393b709e..0dabde0f02c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -18802,6 +18802,13 @@ namespace ts { return !(flow.flags & FlowFlags.PreFinally && (flow).lock.locked) && isReachableFlowNodeWorker(flow, /*skipCacheCheck*/ false); } + function isFalseExpression(expr: Expression): boolean { + const node = skipParentheses(expr); + return node.kind === SyntaxKind.FalseKeyword || node.kind === SyntaxKind.BinaryExpression && ( + (node).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken && (isFalseExpression((node).left) || isFalseExpression((node).right)) || + (node).operatorToken.kind === SyntaxKind.BarBarToken && isFalseExpression((node).left) && isFalseExpression((node).right)); + } + function isReachableFlowNodeWorker(flow: FlowNode, noCacheCheck: boolean): boolean { while (true) { if (flow === lastFlowNode) { @@ -18821,8 +18828,17 @@ namespace ts { } else if (flags & FlowFlags.Call) { const signature = getEffectsSignature((flow).node); - if (signature && getReturnTypeOfSignature(signature).flags & TypeFlags.Never) { - return false; + if (signature) { + const predicate = getTypePredicateOfSignature(signature); + if (predicate && predicate.kind === TypePredicateKind.AssertsIdentifier) { + const predicateArgument = (flow).node.arguments[predicate.parameterIndex]; + if (predicateArgument && isFalseExpression(predicateArgument)) { + return false; + } + } + if (getReturnTypeOfSignature(signature).flags & TypeFlags.Never) { + return false; + } } flow = (flow).antecedent; } @@ -19061,6 +19077,9 @@ namespace ts { function narrowTypeByAssertion(type: Type, expr: Expression): Type { const node = skipParentheses(expr); + if (node.kind === SyntaxKind.FalseKeyword) { + return unreachableNeverType; + } if (node.kind === SyntaxKind.BinaryExpression) { if ((node).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) { return narrowTypeByAssertion(narrowTypeByAssertion(type, (node).left), (node).right); @@ -19080,7 +19099,7 @@ namespace ts { const flowType = getTypeAtFlowNode(flow.antecedent); const type = getTypeFromFlowType(flowType); const narrowedType = predicate.type ? narrowTypeByTypePredicate(type, predicate, flow.node, /*assumeTrue*/ true) : - predicate.kind === TypePredicateKind.AssertsIdentifier ? narrowTypeByAssertion(type, flow.node.arguments[predicate.parameterIndex]) : + predicate.kind === TypePredicateKind.AssertsIdentifier && predicate.parameterIndex >= 0 && predicate.parameterIndex < flow.node.arguments.length ? narrowTypeByAssertion(type, flow.node.arguments[predicate.parameterIndex]) : type; return narrowedType === type ? flowType : createFlowType(narrowedType, isIncomplete(flowType)); } diff --git a/tests/baselines/reference/assertionTypePredicates1.errors.txt b/tests/baselines/reference/assertionTypePredicates1.errors.txt index 2fe95b99548..cefd25aa139 100644 --- a/tests/baselines/reference/assertionTypePredicates1.errors.txt +++ b/tests/baselines/reference/assertionTypePredicates1.errors.txt @@ -1,16 +1,20 @@ -tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(116,37): error TS1228: A type predicate is only allowed in return type position for functions and methods. -tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(117,37): error TS1228: A type predicate is only allowed in return type position for functions and methods. -tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(118,37): error TS1228: A type predicate is only allowed in return type position for functions and methods. -tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(121,15): error TS1228: A type predicate is only allowed in return type position for functions and methods. -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: 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(39,9): error TS7027: Unreachable code detected. +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 (10 errors) ==== +==== tests/cases/conformance/controlFlow/assertionTypePredicates1.ts (14 errors) ==== declare function isString(value: unknown): value is string; declare function isArrayOfStrings(value: unknown): value is string[]; @@ -47,6 +51,18 @@ tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(133,5): error TS assertDefined(x); x; // string } + if (!!true) { + assert(false); + x; // Unreachable + ~~ +!!! error TS7027: Unreachable code detected. + } + if (!!true) { + assert(false && x === undefined); + x; // Unreachable + ~~ +!!! error TS7027: Unreachable code detected. + } } function f02(x: string | undefined) { @@ -87,6 +103,12 @@ tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(133,5): error TS Debug.assertDefined(x); x.length; } + if (!!true) { + Debug.assert(false); + x; // Unreachable + ~~ +!!! error TS7027: Unreachable code detected. + } } class Test { @@ -118,6 +140,12 @@ tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(133,5): error TS this.assertIsTest2(); this.z; } + baz(x: number) { + this.assert(false); + x; // Unreachable + ~~ +!!! error TS7027: Unreachable code detected. + } } class Test2 extends Test { @@ -156,7 +184,7 @@ tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(133,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 TS2728 tests/cases/conformance/controlFlow/assertionTypePredicates1.ts:128:11: 'assert' is declared here. +!!! related TS2728 tests/cases/conformance/controlFlow/assertionTypePredicates1.ts:144:11: 'assert' is declared here. const a = [assert]; a[0](typeof x === "string"); // Error ~~~~ @@ -165,7 +193,7 @@ tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(133,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 TS2728 tests/cases/conformance/controlFlow/assertionTypePredicates1.ts:132:11: 't1' is declared here. +!!! related TS2728 tests/cases/conformance/controlFlow/assertionTypePredicates1.ts:148:11: 't1' is declared here. 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 145bb98bce9..8077e87a797 100644 --- a/tests/baselines/reference/assertionTypePredicates1.js +++ b/tests/baselines/reference/assertionTypePredicates1.js @@ -35,6 +35,14 @@ function f01(x: unknown) { assertDefined(x); x; // string } + if (!!true) { + assert(false); + x; // Unreachable + } + if (!!true) { + assert(false && x === undefined); + x; // Unreachable + } } function f02(x: string | undefined) { @@ -75,6 +83,10 @@ function f10(x: string | undefined) { Debug.assertDefined(x); x.length; } + if (!!true) { + Debug.assert(false); + x; // Unreachable + } } class Test { @@ -106,6 +118,10 @@ class Test { this.assertIsTest2(); this.z; } + baz(x: number) { + this.assert(false); + x; // Unreachable + } } class Test2 extends Test { @@ -180,6 +196,14 @@ function f01(x) { assertDefined(x); x; // string } + if (!!true) { + assert(false); + x; // Unreachable + } + if (!!true) { + assert(false && x === undefined); + x; // Unreachable + } } function f02(x) { if (!!true) { @@ -215,6 +239,10 @@ function f10(x) { Debug.assertDefined(x); x.length; } + if (!!true) { + Debug.assert(false); + x; // Unreachable + } } var Test = /** @class */ (function () { function Test() { @@ -250,6 +278,10 @@ var Test = /** @class */ (function () { this.assertIsTest2(); this.z; }; + Test.prototype.baz = function (x) { + this.assert(false); + x; // Unreachable + }; return Test; }()); var Test2 = /** @class */ (function (_super) { @@ -295,6 +327,7 @@ declare class Test { assertThis(): asserts this; bar(): void; foo(x: unknown): void; + baz(x: number): void; } declare class Test2 extends Test { z: number; diff --git a/tests/baselines/reference/assertionTypePredicates1.symbols b/tests/baselines/reference/assertionTypePredicates1.symbols index af43ab29864..758d5eddfe9 100644 --- a/tests/baselines/reference/assertionTypePredicates1.symbols +++ b/tests/baselines/reference/assertionTypePredicates1.symbols @@ -106,297 +106,334 @@ function f01(x: unknown) { >x : Symbol(x, Decl(assertionTypePredicates1.ts, 9, 13)) x; // string +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 9, 13)) + } + if (!!true) { + assert(false); +>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 3, 5)) + + x; // Unreachable +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 9, 13)) + } + if (!!true) { + assert(false && x === undefined); +>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 3, 5)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 9, 13)) +>undefined : Symbol(undefined) + + x; // Unreachable >x : Symbol(x, Decl(assertionTypePredicates1.ts, 9, 13)) } } function f02(x: string | undefined) { ->f02 : Symbol(f02, Decl(assertionTypePredicates1.ts, 36, 1)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 38, 13)) +>f02 : Symbol(f02, Decl(assertionTypePredicates1.ts, 44, 1)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 46, 13)) if (!!true) { assert(x); >assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 3, 5)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 38, 13)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 46, 13)) x.length; >x.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 38, 13)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 46, 13)) >length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) } if (!!true) { assert(x !== undefined); >assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 3, 5)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 38, 13)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 46, 13)) >undefined : Symbol(undefined) x.length; >x.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 38, 13)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 46, 13)) >length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) } if (!!true) { assertDefined(x); >assertDefined : Symbol(assertDefined, Decl(assertionTypePredicates1.ts, 6, 83)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 38, 13)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 46, 13)) x.length; >x.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 38, 13)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 46, 13)) >length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) } } function f03(x: string | undefined, assert: (value: unknown) => asserts value) { ->f03 : Symbol(f03, Decl(assertionTypePredicates1.ts, 51, 1)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 53, 13)) ->assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 53, 35)) ->value : Symbol(value, Decl(assertionTypePredicates1.ts, 53, 45)) ->value : Symbol(value, Decl(assertionTypePredicates1.ts, 53, 45)) +>f03 : Symbol(f03, Decl(assertionTypePredicates1.ts, 59, 1)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 61, 13)) +>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 61, 35)) +>value : Symbol(value, Decl(assertionTypePredicates1.ts, 61, 45)) +>value : Symbol(value, Decl(assertionTypePredicates1.ts, 61, 45)) assert(x); ->assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 53, 35)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 53, 13)) +>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 61, 35)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 61, 13)) x.length; >x.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 53, 13)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 61, 13)) >length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) } namespace Debug { ->Debug : Symbol(Debug, Decl(assertionTypePredicates1.ts, 56, 1)) +>Debug : Symbol(Debug, Decl(assertionTypePredicates1.ts, 64, 1)) export declare function assert(value: unknown, message?: string): asserts value; ->assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 58, 17)) ->value : Symbol(value, Decl(assertionTypePredicates1.ts, 59, 35)) ->message : Symbol(message, Decl(assertionTypePredicates1.ts, 59, 50)) ->value : Symbol(value, Decl(assertionTypePredicates1.ts, 59, 35)) +>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 66, 17)) +>value : Symbol(value, Decl(assertionTypePredicates1.ts, 67, 35)) +>message : Symbol(message, Decl(assertionTypePredicates1.ts, 67, 50)) +>value : Symbol(value, Decl(assertionTypePredicates1.ts, 67, 35)) export declare function assertDefined(value: T): asserts value is NonNullable; ->assertDefined : Symbol(assertDefined, Decl(assertionTypePredicates1.ts, 59, 84)) ->T : Symbol(T, Decl(assertionTypePredicates1.ts, 60, 42)) ->value : Symbol(value, Decl(assertionTypePredicates1.ts, 60, 45)) ->T : Symbol(T, Decl(assertionTypePredicates1.ts, 60, 42)) ->value : Symbol(value, Decl(assertionTypePredicates1.ts, 60, 45)) +>assertDefined : Symbol(assertDefined, Decl(assertionTypePredicates1.ts, 67, 84)) +>T : Symbol(T, Decl(assertionTypePredicates1.ts, 68, 42)) +>value : Symbol(value, Decl(assertionTypePredicates1.ts, 68, 45)) +>T : Symbol(T, Decl(assertionTypePredicates1.ts, 68, 42)) +>value : Symbol(value, Decl(assertionTypePredicates1.ts, 68, 45)) >NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --)) ->T : Symbol(T, Decl(assertionTypePredicates1.ts, 60, 42)) +>T : Symbol(T, Decl(assertionTypePredicates1.ts, 68, 42)) } function f10(x: string | undefined) { ->f10 : Symbol(f10, Decl(assertionTypePredicates1.ts, 61, 1)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 63, 13)) +>f10 : Symbol(f10, Decl(assertionTypePredicates1.ts, 69, 1)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 71, 13)) if (!!true) { Debug.assert(x); ->Debug.assert : Symbol(Debug.assert, Decl(assertionTypePredicates1.ts, 58, 17)) ->Debug : Symbol(Debug, Decl(assertionTypePredicates1.ts, 56, 1)) ->assert : Symbol(Debug.assert, Decl(assertionTypePredicates1.ts, 58, 17)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 63, 13)) +>Debug.assert : Symbol(Debug.assert, Decl(assertionTypePredicates1.ts, 66, 17)) +>Debug : Symbol(Debug, Decl(assertionTypePredicates1.ts, 64, 1)) +>assert : Symbol(Debug.assert, Decl(assertionTypePredicates1.ts, 66, 17)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 71, 13)) x.length; >x.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 63, 13)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 71, 13)) >length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) } if (!!true) { Debug.assert(x !== undefined); ->Debug.assert : Symbol(Debug.assert, Decl(assertionTypePredicates1.ts, 58, 17)) ->Debug : Symbol(Debug, Decl(assertionTypePredicates1.ts, 56, 1)) ->assert : Symbol(Debug.assert, Decl(assertionTypePredicates1.ts, 58, 17)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 63, 13)) +>Debug.assert : Symbol(Debug.assert, Decl(assertionTypePredicates1.ts, 66, 17)) +>Debug : Symbol(Debug, Decl(assertionTypePredicates1.ts, 64, 1)) +>assert : Symbol(Debug.assert, Decl(assertionTypePredicates1.ts, 66, 17)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 71, 13)) >undefined : Symbol(undefined) x.length; >x.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 63, 13)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 71, 13)) >length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) } if (!!true) { Debug.assertDefined(x); ->Debug.assertDefined : Symbol(Debug.assertDefined, Decl(assertionTypePredicates1.ts, 59, 84)) ->Debug : Symbol(Debug, Decl(assertionTypePredicates1.ts, 56, 1)) ->assertDefined : Symbol(Debug.assertDefined, Decl(assertionTypePredicates1.ts, 59, 84)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 63, 13)) +>Debug.assertDefined : Symbol(Debug.assertDefined, Decl(assertionTypePredicates1.ts, 67, 84)) +>Debug : Symbol(Debug, Decl(assertionTypePredicates1.ts, 64, 1)) +>assertDefined : Symbol(Debug.assertDefined, Decl(assertionTypePredicates1.ts, 67, 84)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 71, 13)) x.length; >x.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 63, 13)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 71, 13)) >length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) } + if (!!true) { + Debug.assert(false); +>Debug.assert : Symbol(Debug.assert, Decl(assertionTypePredicates1.ts, 66, 17)) +>Debug : Symbol(Debug, Decl(assertionTypePredicates1.ts, 64, 1)) +>assert : Symbol(Debug.assert, Decl(assertionTypePredicates1.ts, 66, 17)) + + x; // Unreachable +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 71, 13)) + } } class Test { ->Test : Symbol(Test, Decl(assertionTypePredicates1.ts, 76, 1)) +>Test : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1)) assert(value: unknown): asserts value { ->assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 78, 12)) ->value : Symbol(value, Decl(assertionTypePredicates1.ts, 79, 11)) ->value : Symbol(value, Decl(assertionTypePredicates1.ts, 79, 11)) +>assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12)) +>value : Symbol(value, Decl(assertionTypePredicates1.ts, 91, 11)) +>value : Symbol(value, Decl(assertionTypePredicates1.ts, 91, 11)) if (value) return; ->value : Symbol(value, Decl(assertionTypePredicates1.ts, 79, 11)) +>value : Symbol(value, Decl(assertionTypePredicates1.ts, 91, 11)) throw new Error(); >Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) } isTest2(): this is Test2 { ->isTest2 : Symbol(Test.isTest2, Decl(assertionTypePredicates1.ts, 82, 5)) ->Test2 : Symbol(Test2, Decl(assertionTypePredicates1.ts, 107, 1)) +>isTest2 : Symbol(Test.isTest2, Decl(assertionTypePredicates1.ts, 94, 5)) +>Test2 : Symbol(Test2, Decl(assertionTypePredicates1.ts, 123, 1)) return this instanceof Test2; ->this : Symbol(Test, Decl(assertionTypePredicates1.ts, 76, 1)) ->Test2 : Symbol(Test2, Decl(assertionTypePredicates1.ts, 107, 1)) +>this : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1)) +>Test2 : Symbol(Test2, Decl(assertionTypePredicates1.ts, 123, 1)) } assertIsTest2(): asserts this is Test2 { ->assertIsTest2 : Symbol(Test.assertIsTest2, Decl(assertionTypePredicates1.ts, 85, 5)) ->Test2 : Symbol(Test2, Decl(assertionTypePredicates1.ts, 107, 1)) +>assertIsTest2 : Symbol(Test.assertIsTest2, Decl(assertionTypePredicates1.ts, 97, 5)) +>Test2 : Symbol(Test2, Decl(assertionTypePredicates1.ts, 123, 1)) if (this instanceof Test2) return; ->this : Symbol(Test, Decl(assertionTypePredicates1.ts, 76, 1)) ->Test2 : Symbol(Test2, Decl(assertionTypePredicates1.ts, 107, 1)) +>this : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1)) +>Test2 : Symbol(Test2, Decl(assertionTypePredicates1.ts, 123, 1)) throw new Error(); >Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) } assertThis(): asserts this { ->assertThis : Symbol(Test.assertThis, Decl(assertionTypePredicates1.ts, 89, 5)) +>assertThis : Symbol(Test.assertThis, Decl(assertionTypePredicates1.ts, 101, 5)) if (!this) return; ->this : Symbol(Test, Decl(assertionTypePredicates1.ts, 76, 1)) +>this : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1)) throw new Error(); >Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) } bar() { ->bar : Symbol(Test.bar, Decl(assertionTypePredicates1.ts, 93, 5)) +>bar : Symbol(Test.bar, Decl(assertionTypePredicates1.ts, 105, 5)) this.assertThis(); ->this.assertThis : Symbol(Test.assertThis, Decl(assertionTypePredicates1.ts, 89, 5)) ->this : Symbol(Test, Decl(assertionTypePredicates1.ts, 76, 1)) ->assertThis : Symbol(Test.assertThis, Decl(assertionTypePredicates1.ts, 89, 5)) +>this.assertThis : Symbol(Test.assertThis, Decl(assertionTypePredicates1.ts, 101, 5)) +>this : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1)) +>assertThis : Symbol(Test.assertThis, Decl(assertionTypePredicates1.ts, 101, 5)) this; ->this : Symbol(Test, Decl(assertionTypePredicates1.ts, 76, 1)) +>this : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1)) } foo(x: unknown) { ->foo : Symbol(Test.foo, Decl(assertionTypePredicates1.ts, 97, 5)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 98, 8)) +>foo : Symbol(Test.foo, Decl(assertionTypePredicates1.ts, 109, 5)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 110, 8)) this.assert(typeof x === "string"); ->this.assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 78, 12)) ->this : Symbol(Test, Decl(assertionTypePredicates1.ts, 76, 1)) ->assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 78, 12)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 98, 8)) +>this.assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12)) +>this : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1)) +>assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 110, 8)) x.length; >x.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 98, 8)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 110, 8)) >length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) if (this.isTest2()) { ->this.isTest2 : Symbol(Test.isTest2, Decl(assertionTypePredicates1.ts, 82, 5)) ->this : Symbol(Test, Decl(assertionTypePredicates1.ts, 76, 1)) ->isTest2 : Symbol(Test.isTest2, Decl(assertionTypePredicates1.ts, 82, 5)) +>this.isTest2 : Symbol(Test.isTest2, Decl(assertionTypePredicates1.ts, 94, 5)) +>this : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1)) +>isTest2 : Symbol(Test.isTest2, Decl(assertionTypePredicates1.ts, 94, 5)) this.z; ->this.z : Symbol(Test2.z, Decl(assertionTypePredicates1.ts, 109, 26)) ->z : Symbol(Test2.z, Decl(assertionTypePredicates1.ts, 109, 26)) +>this.z : Symbol(Test2.z, Decl(assertionTypePredicates1.ts, 125, 26)) +>z : Symbol(Test2.z, Decl(assertionTypePredicates1.ts, 125, 26)) } this.assertIsTest2(); ->this.assertIsTest2 : Symbol(Test.assertIsTest2, Decl(assertionTypePredicates1.ts, 85, 5)) ->this : Symbol(Test, Decl(assertionTypePredicates1.ts, 76, 1)) ->assertIsTest2 : Symbol(Test.assertIsTest2, Decl(assertionTypePredicates1.ts, 85, 5)) +>this.assertIsTest2 : Symbol(Test.assertIsTest2, Decl(assertionTypePredicates1.ts, 97, 5)) +>this : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1)) +>assertIsTest2 : Symbol(Test.assertIsTest2, Decl(assertionTypePredicates1.ts, 97, 5)) this.z; ->this.z : Symbol(Test2.z, Decl(assertionTypePredicates1.ts, 109, 26)) ->z : Symbol(Test2.z, Decl(assertionTypePredicates1.ts, 109, 26)) +>this.z : Symbol(Test2.z, Decl(assertionTypePredicates1.ts, 125, 26)) +>z : Symbol(Test2.z, Decl(assertionTypePredicates1.ts, 125, 26)) + } + baz(x: number) { +>baz : Symbol(Test.baz, Decl(assertionTypePredicates1.ts, 118, 5)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 119, 8)) + + this.assert(false); +>this.assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12)) +>this : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1)) +>assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12)) + + x; // Unreachable +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 119, 8)) } } class Test2 extends Test { ->Test2 : Symbol(Test2, Decl(assertionTypePredicates1.ts, 107, 1)) ->Test : Symbol(Test, Decl(assertionTypePredicates1.ts, 76, 1)) +>Test2 : Symbol(Test2, Decl(assertionTypePredicates1.ts, 123, 1)) +>Test : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1)) z = 0; ->z : Symbol(Test2.z, Decl(assertionTypePredicates1.ts, 109, 26)) +>z : Symbol(Test2.z, Decl(assertionTypePredicates1.ts, 125, 26)) } // Invalid constructs declare let Q1: new (x: unknown) => x is string; ->Q1 : Symbol(Q1, Decl(assertionTypePredicates1.ts, 115, 11)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 115, 21)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 115, 21)) +>Q1 : Symbol(Q1, Decl(assertionTypePredicates1.ts, 131, 11)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 131, 21)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 131, 21)) declare let Q2: new (x: boolean) => asserts x; ->Q2 : Symbol(Q2, Decl(assertionTypePredicates1.ts, 116, 11)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 116, 21)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 116, 21)) +>Q2 : Symbol(Q2, Decl(assertionTypePredicates1.ts, 132, 11)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 132, 21)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 132, 21)) declare let Q3: new (x: unknown) => asserts x is string; ->Q3 : Symbol(Q3, Decl(assertionTypePredicates1.ts, 117, 11)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 117, 21)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 117, 21)) +>Q3 : Symbol(Q3, Decl(assertionTypePredicates1.ts, 133, 11)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 133, 21)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 133, 21)) declare class Wat { ->Wat : Symbol(Wat, Decl(assertionTypePredicates1.ts, 117, 56)) +>Wat : Symbol(Wat, Decl(assertionTypePredicates1.ts, 133, 56)) get p1(): this is string; ->p1 : Symbol(Wat.p1, Decl(assertionTypePredicates1.ts, 119, 19), Decl(assertionTypePredicates1.ts, 120, 29)) +>p1 : Symbol(Wat.p1, Decl(assertionTypePredicates1.ts, 135, 19), Decl(assertionTypePredicates1.ts, 136, 29)) set p1(x: this is string); ->p1 : Symbol(Wat.p1, Decl(assertionTypePredicates1.ts, 119, 19), Decl(assertionTypePredicates1.ts, 120, 29)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 121, 11)) +>p1 : Symbol(Wat.p1, Decl(assertionTypePredicates1.ts, 135, 19), Decl(assertionTypePredicates1.ts, 136, 29)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 137, 11)) get p2(): asserts this is string; ->p2 : Symbol(Wat.p2, Decl(assertionTypePredicates1.ts, 121, 30), Decl(assertionTypePredicates1.ts, 122, 37)) +>p2 : Symbol(Wat.p2, Decl(assertionTypePredicates1.ts, 137, 30), Decl(assertionTypePredicates1.ts, 138, 37)) set p2(x: asserts this is string); ->p2 : Symbol(Wat.p2, Decl(assertionTypePredicates1.ts, 121, 30), Decl(assertionTypePredicates1.ts, 122, 37)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 123, 11)) +>p2 : Symbol(Wat.p2, Decl(assertionTypePredicates1.ts, 137, 30), Decl(assertionTypePredicates1.ts, 138, 37)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 139, 11)) } function f20(x: unknown) { ->f20 : Symbol(f20, Decl(assertionTypePredicates1.ts, 124, 1)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 126, 13)) +>f20 : Symbol(f20, Decl(assertionTypePredicates1.ts, 140, 1)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 142, 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 : Symbol(assert, Decl(assertionTypePredicates1.ts, 143, 9)) +>value : Symbol(value, Decl(assertionTypePredicates1.ts, 143, 20)) +>value : Symbol(value, Decl(assertionTypePredicates1.ts, 143, 20)) assert(typeof x === "string"); // Error ->assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 127, 9)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 126, 13)) +>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 143, 9)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 142, 13)) const a = [assert]; ->a : Symbol(a, Decl(assertionTypePredicates1.ts, 129, 9)) ->assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 127, 9)) +>a : Symbol(a, Decl(assertionTypePredicates1.ts, 145, 9)) +>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 143, 9)) a[0](typeof x === "string"); // Error ->a : Symbol(a, Decl(assertionTypePredicates1.ts, 129, 9)) ->x : Symbol(x, Decl(assertionTypePredicates1.ts, 126, 13)) +>a : Symbol(a, Decl(assertionTypePredicates1.ts, 145, 9)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 142, 13)) const t1 = new Test(); ->t1 : Symbol(t1, Decl(assertionTypePredicates1.ts, 131, 9)) ->Test : Symbol(Test, Decl(assertionTypePredicates1.ts, 76, 1)) +>t1 : Symbol(t1, Decl(assertionTypePredicates1.ts, 147, 9)) +>Test : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 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)) +>t1.assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12)) +>t1 : Symbol(t1, Decl(assertionTypePredicates1.ts, 147, 9)) +>assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 142, 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 : Symbol(t2, Decl(assertionTypePredicates1.ts, 149, 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, 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)) +>t2.assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12)) +>t2 : Symbol(t2, Decl(assertionTypePredicates1.ts, 149, 9)) +>assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12)) +>x : Symbol(x, Decl(assertionTypePredicates1.ts, 142, 13)) } diff --git a/tests/baselines/reference/assertionTypePredicates1.types b/tests/baselines/reference/assertionTypePredicates1.types index 470478b3fe4..ac4100fb449 100644 --- a/tests/baselines/reference/assertionTypePredicates1.types +++ b/tests/baselines/reference/assertionTypePredicates1.types @@ -151,6 +151,36 @@ function f01(x: unknown) { x; // string >x : string } + if (!!true) { +>!!true : true +>!true : false +>true : true + + assert(false); +>assert(false) : void +>assert : (value: unknown) => asserts value +>false : false + + x; // Unreachable +>x : unknown + } + if (!!true) { +>!!true : true +>!true : false +>true : true + + assert(false && x === undefined); +>assert(false && x === undefined) : void +>assert : (value: unknown) => asserts value +>false && x === undefined : false +>false : false +>x === undefined : boolean +>x : unknown +>undefined : undefined + + x; // Unreachable +>x : unknown + } } function f02(x: string | undefined) { @@ -293,6 +323,21 @@ function f10(x: string | undefined) { >x : string >length : number } + if (!!true) { +>!!true : true +>!true : false +>true : true + + Debug.assert(false); +>Debug.assert(false) : void +>Debug.assert : (value: unknown, message?: string | undefined) => asserts value +>Debug : typeof Debug +>assert : (value: unknown, message?: string | undefined) => asserts value +>false : false + + x; // Unreachable +>x : string | undefined + } } class Test { @@ -393,6 +438,20 @@ class Test { >this : this & Test2 >z : number } + baz(x: number) { +>baz : (x: number) => void +>x : number + + this.assert(false); +>this.assert(false) : void +>this.assert : (value: unknown) => asserts value +>this : this +>assert : (value: unknown) => asserts value +>false : false + + x; // Unreachable +>x : number + } } class Test2 extends Test { diff --git a/tests/cases/conformance/controlFlow/assertionTypePredicates1.ts b/tests/cases/conformance/controlFlow/assertionTypePredicates1.ts index 4cc73d5c917..1b7db7affaa 100644 --- a/tests/cases/conformance/controlFlow/assertionTypePredicates1.ts +++ b/tests/cases/conformance/controlFlow/assertionTypePredicates1.ts @@ -1,4 +1,5 @@ // @strict: true +// @allowUnreachableCode: false // @declaration: true declare function isString(value: unknown): value is string; @@ -37,6 +38,14 @@ function f01(x: unknown) { assertDefined(x); x; // string } + if (!!true) { + assert(false); + x; // Unreachable + } + if (!!true) { + assert(false && x === undefined); + x; // Unreachable + } } function f02(x: string | undefined) { @@ -77,6 +86,10 @@ function f10(x: string | undefined) { Debug.assertDefined(x); x.length; } + if (!!true) { + Debug.assert(false); + x; // Unreachable + } } class Test { @@ -108,6 +121,10 @@ class Test { this.assertIsTest2(); this.z; } + baz(x: number) { + this.assert(false); + x; // Unreachable + } } class Test2 extends Test {