From 7265f496ebf6faf6b2efe273483f8ed225fb0e99 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Thu, 19 Nov 2020 09:59:52 -0800 Subject: [PATCH] Improve uncalled function checks Fixes #41586 Fixes #41588 1. For binary expressions, if the immediate parent is an IfStatement, then check the body of the if statement. I didn't walk upward to find an IfStatement because in my experimentation I found that binary expression uncalled-function errors are only issued when the expression is on the left of the top-most binary expression. 2. For property accesses with interspersed calls, I added a CallExpression case. In fact, any expression could appear here, but I only want to fix calls for now since that's all we've observed in Definitely Typed, and we didn't see anything else in the user tests or RWC tests. I also didn't examine parameters of the intermediate call expressions, but I don't think it's needed since the intent is to avoid false positives. --- src/compiler/checker.ts | 16 +- ...uthinessCallExpressionCoercion1.errors.txt | 17 +- .../truthinessCallExpressionCoercion1.js | 29 +++ .../truthinessCallExpressionCoercion1.symbols | 71 +++++-- .../truthinessCallExpressionCoercion1.types | 46 +++++ ...uthinessCallExpressionCoercion2.errors.txt | 27 ++- .../truthinessCallExpressionCoercion2.js | 19 +- .../truthinessCallExpressionCoercion2.symbols | 191 ++++++++++-------- .../truthinessCallExpressionCoercion2.types | 22 +- .../truthinessCallExpressionCoercion1.ts | 15 ++ .../truthinessCallExpressionCoercion2.ts | 10 +- 11 files changed, 338 insertions(+), 125 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 474296b13f061..b6d00e24701f8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -30172,7 +30172,7 @@ namespace ts { const operator = node.operatorToken.kind; if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken || operator === SyntaxKind.QuestionQuestionToken) { if (operator === SyntaxKind.AmpersandAmpersandToken) { - checkTestingKnownTruthyCallableType(node.left, leftType); + checkTestingKnownTruthyCallableType(node.left, leftType, isIfStatement(node.parent) ? node.parent.thenStatement : undefined); } checkTruthinessOfType(leftType, node.left); } @@ -33954,7 +33954,7 @@ namespace ts { checkSourceElement(node.elseStatement); } - function checkTestingKnownTruthyCallableType(condExpr: Expression, type: Type, body?: Statement | Expression) { + function checkTestingKnownTruthyCallableType(condExpr: Expression, type: Type, body: Statement | Expression | undefined) { if (!strictNullChecks) { return; } @@ -33989,9 +33989,8 @@ namespace ts { return; } - const isUsed = isBinaryExpression(condExpr.parent) ? isFunctionUsedInBinaryExpressionChain(condExpr.parent, testedSymbol) - : body ? isFunctionUsedInConditionBody(condExpr, body, testedNode, testedSymbol) - : false; + const isUsed = isBinaryExpression(condExpr.parent) && isFunctionUsedInBinaryExpressionChain(condExpr.parent, testedSymbol) + || body && isFunctionUsedInConditionBody(condExpr, body, testedNode, testedSymbol); if (!isUsed) { error(location, Diagnostics.This_condition_will_always_return_true_since_the_function_is_always_defined_Did_you_mean_to_call_it_instead); } @@ -34014,14 +34013,17 @@ namespace ts { testedExpression.kind === SyntaxKind.ThisKeyword && childExpression.kind === SyntaxKind.ThisKeyword) { return getSymbolAtLocation(testedExpression) === getSymbolAtLocation(childExpression); } - - if (isPropertyAccessExpression(testedExpression) && isPropertyAccessExpression(childExpression)) { + else if (isPropertyAccessExpression(testedExpression) && isPropertyAccessExpression(childExpression)) { if (getSymbolAtLocation(testedExpression.name) !== getSymbolAtLocation(childExpression.name)) { return false; } childExpression = childExpression.expression; testedExpression = testedExpression.expression; } + else if (isCallExpression(testedExpression) && isCallExpression(childExpression)) { + childExpression = childExpression.expression; + testedExpression = testedExpression.expression; + } else { return false; } diff --git a/tests/baselines/reference/truthinessCallExpressionCoercion1.errors.txt b/tests/baselines/reference/truthinessCallExpressionCoercion1.errors.txt index e30041e220ae5..ed7ba0a570973 100644 --- a/tests/baselines/reference/truthinessCallExpressionCoercion1.errors.txt +++ b/tests/baselines/reference/truthinessCallExpressionCoercion1.errors.txt @@ -2,7 +2,7 @@ tests/cases/compiler/truthinessCallExpressionCoercion1.ts(3,5): error TS2774: Th tests/cases/compiler/truthinessCallExpressionCoercion1.ts(19,5): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead? tests/cases/compiler/truthinessCallExpressionCoercion1.ts(33,5): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead? tests/cases/compiler/truthinessCallExpressionCoercion1.ts(46,5): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead? -tests/cases/compiler/truthinessCallExpressionCoercion1.ts(61,9): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead? +tests/cases/compiler/truthinessCallExpressionCoercion1.ts(76,9): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead? ==== tests/cases/compiler/truthinessCallExpressionCoercion1.ts (5 errors) ==== @@ -63,6 +63,21 @@ tests/cases/compiler/truthinessCallExpressionCoercion1.ts(61,9): error TS2774: T // ok x.foo.bar ? x.foo.bar : undefined; + + var chrome = { + platformKeys: { + subtleCrypto() { + return { + sign() {}, + exportKey() { return true } + } + } + } + } + // ok + if (chrome.platformKeys.subtleCrypto().exportKey) { + chrome.platformKeys.subtleCrypto().exportKey + } } class Foo { diff --git a/tests/baselines/reference/truthinessCallExpressionCoercion1.js b/tests/baselines/reference/truthinessCallExpressionCoercion1.js index ecb76aadf897b..482f64a6b4946 100644 --- a/tests/baselines/reference/truthinessCallExpressionCoercion1.js +++ b/tests/baselines/reference/truthinessCallExpressionCoercion1.js @@ -48,6 +48,21 @@ function checksPropertyAccess() { // ok x.foo.bar ? x.foo.bar : undefined; + + var chrome = { + platformKeys: { + subtleCrypto() { + return { + sign() {}, + exportKey() { return true } + } + } + } + } + // ok + if (chrome.platformKeys.subtleCrypto().exportKey) { + chrome.platformKeys.subtleCrypto().exportKey + } } class Foo { @@ -110,6 +125,20 @@ function checksPropertyAccess() { x.foo.bar ? console.log('x.foo.bar') : undefined; // ok x.foo.bar ? x.foo.bar : undefined; + var chrome = { + platformKeys: { + subtleCrypto: function () { + return { + sign: function () { }, + exportKey: function () { return true; } + }; + } + } + }; + // ok + if (chrome.platformKeys.subtleCrypto().exportKey) { + chrome.platformKeys.subtleCrypto().exportKey; + } } var Foo = /** @class */ (function () { function Foo() { diff --git a/tests/baselines/reference/truthinessCallExpressionCoercion1.symbols b/tests/baselines/reference/truthinessCallExpressionCoercion1.symbols index aace0d3c5562e..a19bd07d36dd6 100644 --- a/tests/baselines/reference/truthinessCallExpressionCoercion1.symbols +++ b/tests/baselines/reference/truthinessCallExpressionCoercion1.symbols @@ -134,28 +134,67 @@ function checksPropertyAccess() { >foo : Symbol(foo, Decl(truthinessCallExpressionCoercion1.ts, 38, 15)) >bar : Symbol(bar, Decl(truthinessCallExpressionCoercion1.ts, 39, 14)) >undefined : Symbol(undefined) + + var chrome = { +>chrome : Symbol(chrome, Decl(truthinessCallExpressionCoercion1.ts, 50, 7)) + + platformKeys: { +>platformKeys : Symbol(platformKeys, Decl(truthinessCallExpressionCoercion1.ts, 50, 18)) + + subtleCrypto() { +>subtleCrypto : Symbol(subtleCrypto, Decl(truthinessCallExpressionCoercion1.ts, 51, 23)) + + return { + sign() {}, +>sign : Symbol(sign, Decl(truthinessCallExpressionCoercion1.ts, 53, 24)) + + exportKey() { return true } +>exportKey : Symbol(exportKey, Decl(truthinessCallExpressionCoercion1.ts, 54, 30)) + } + } + } + } + // ok + if (chrome.platformKeys.subtleCrypto().exportKey) { +>chrome.platformKeys.subtleCrypto().exportKey : Symbol(exportKey, Decl(truthinessCallExpressionCoercion1.ts, 54, 30)) +>chrome.platformKeys.subtleCrypto : Symbol(subtleCrypto, Decl(truthinessCallExpressionCoercion1.ts, 51, 23)) +>chrome.platformKeys : Symbol(platformKeys, Decl(truthinessCallExpressionCoercion1.ts, 50, 18)) +>chrome : Symbol(chrome, Decl(truthinessCallExpressionCoercion1.ts, 50, 7)) +>platformKeys : Symbol(platformKeys, Decl(truthinessCallExpressionCoercion1.ts, 50, 18)) +>subtleCrypto : Symbol(subtleCrypto, Decl(truthinessCallExpressionCoercion1.ts, 51, 23)) +>exportKey : Symbol(exportKey, Decl(truthinessCallExpressionCoercion1.ts, 54, 30)) + + chrome.platformKeys.subtleCrypto().exportKey +>chrome.platformKeys.subtleCrypto().exportKey : Symbol(exportKey, Decl(truthinessCallExpressionCoercion1.ts, 54, 30)) +>chrome.platformKeys.subtleCrypto : Symbol(subtleCrypto, Decl(truthinessCallExpressionCoercion1.ts, 51, 23)) +>chrome.platformKeys : Symbol(platformKeys, Decl(truthinessCallExpressionCoercion1.ts, 50, 18)) +>chrome : Symbol(chrome, Decl(truthinessCallExpressionCoercion1.ts, 50, 7)) +>platformKeys : Symbol(platformKeys, Decl(truthinessCallExpressionCoercion1.ts, 50, 18)) +>subtleCrypto : Symbol(subtleCrypto, Decl(truthinessCallExpressionCoercion1.ts, 51, 23)) +>exportKey : Symbol(exportKey, Decl(truthinessCallExpressionCoercion1.ts, 54, 30)) + } } class Foo { ->Foo : Symbol(Foo, Decl(truthinessCallExpressionCoercion1.ts, 49, 1)) +>Foo : Symbol(Foo, Decl(truthinessCallExpressionCoercion1.ts, 64, 1)) maybeIsUser?: () => boolean; ->maybeIsUser : Symbol(Foo.maybeIsUser, Decl(truthinessCallExpressionCoercion1.ts, 51, 11)) +>maybeIsUser : Symbol(Foo.maybeIsUser, Decl(truthinessCallExpressionCoercion1.ts, 66, 11)) isUser() { ->isUser : Symbol(Foo.isUser, Decl(truthinessCallExpressionCoercion1.ts, 52, 32)) +>isUser : Symbol(Foo.isUser, Decl(truthinessCallExpressionCoercion1.ts, 67, 32)) return true; } test() { ->test : Symbol(Foo.test, Decl(truthinessCallExpressionCoercion1.ts, 56, 5)) +>test : Symbol(Foo.test, Decl(truthinessCallExpressionCoercion1.ts, 71, 5)) // error this.isUser ? console.log('this.isUser') : undefined; ->this.isUser : Symbol(Foo.isUser, Decl(truthinessCallExpressionCoercion1.ts, 52, 32)) ->this : Symbol(Foo, Decl(truthinessCallExpressionCoercion1.ts, 49, 1)) ->isUser : Symbol(Foo.isUser, Decl(truthinessCallExpressionCoercion1.ts, 52, 32)) +>this.isUser : Symbol(Foo.isUser, Decl(truthinessCallExpressionCoercion1.ts, 67, 32)) +>this : Symbol(Foo, Decl(truthinessCallExpressionCoercion1.ts, 64, 1)) +>isUser : Symbol(Foo.isUser, Decl(truthinessCallExpressionCoercion1.ts, 67, 32)) >console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) >console : Symbol(console, Decl(lib.dom.d.ts, --, --)) >log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) @@ -163,9 +202,9 @@ class Foo { // ok this.maybeIsUser ? console.log('this.maybeIsUser') : undefined; ->this.maybeIsUser : Symbol(Foo.maybeIsUser, Decl(truthinessCallExpressionCoercion1.ts, 51, 11)) ->this : Symbol(Foo, Decl(truthinessCallExpressionCoercion1.ts, 49, 1)) ->maybeIsUser : Symbol(Foo.maybeIsUser, Decl(truthinessCallExpressionCoercion1.ts, 51, 11)) +>this.maybeIsUser : Symbol(Foo.maybeIsUser, Decl(truthinessCallExpressionCoercion1.ts, 66, 11)) +>this : Symbol(Foo, Decl(truthinessCallExpressionCoercion1.ts, 64, 1)) +>maybeIsUser : Symbol(Foo.maybeIsUser, Decl(truthinessCallExpressionCoercion1.ts, 66, 11)) >console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) >console : Symbol(console, Decl(lib.dom.d.ts, --, --)) >log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) @@ -173,14 +212,14 @@ class Foo { // ok if (this.isUser) { ->this.isUser : Symbol(Foo.isUser, Decl(truthinessCallExpressionCoercion1.ts, 52, 32)) ->this : Symbol(Foo, Decl(truthinessCallExpressionCoercion1.ts, 49, 1)) ->isUser : Symbol(Foo.isUser, Decl(truthinessCallExpressionCoercion1.ts, 52, 32)) +>this.isUser : Symbol(Foo.isUser, Decl(truthinessCallExpressionCoercion1.ts, 67, 32)) +>this : Symbol(Foo, Decl(truthinessCallExpressionCoercion1.ts, 64, 1)) +>isUser : Symbol(Foo.isUser, Decl(truthinessCallExpressionCoercion1.ts, 67, 32)) this.isUser(); ->this.isUser : Symbol(Foo.isUser, Decl(truthinessCallExpressionCoercion1.ts, 52, 32)) ->this : Symbol(Foo, Decl(truthinessCallExpressionCoercion1.ts, 49, 1)) ->isUser : Symbol(Foo.isUser, Decl(truthinessCallExpressionCoercion1.ts, 52, 32)) +>this.isUser : Symbol(Foo.isUser, Decl(truthinessCallExpressionCoercion1.ts, 67, 32)) +>this : Symbol(Foo, Decl(truthinessCallExpressionCoercion1.ts, 64, 1)) +>isUser : Symbol(Foo.isUser, Decl(truthinessCallExpressionCoercion1.ts, 67, 32)) } } } diff --git a/tests/baselines/reference/truthinessCallExpressionCoercion1.types b/tests/baselines/reference/truthinessCallExpressionCoercion1.types index bcbde0d35f612..cd9f357a5ed4c 100644 --- a/tests/baselines/reference/truthinessCallExpressionCoercion1.types +++ b/tests/baselines/reference/truthinessCallExpressionCoercion1.types @@ -180,6 +180,52 @@ function checksPropertyAccess() { >foo : { bar(): boolean; } >bar : () => boolean >undefined : undefined + + var chrome = { +>chrome : { platformKeys: { subtleCrypto(): { sign(): void; exportKey(): boolean; }; }; } +>{ platformKeys: { subtleCrypto() { return { sign() {}, exportKey() { return true } } } } } : { platformKeys: { subtleCrypto(): { sign(): void; exportKey(): boolean; }; }; } + + platformKeys: { +>platformKeys : { subtleCrypto(): { sign(): void; exportKey(): boolean; }; } +>{ subtleCrypto() { return { sign() {}, exportKey() { return true } } } } : { subtleCrypto(): { sign(): void; exportKey(): boolean; }; } + + subtleCrypto() { +>subtleCrypto : () => { sign(): void; exportKey(): boolean; } + + return { +>{ sign() {}, exportKey() { return true } } : { sign(): void; exportKey(): boolean; } + + sign() {}, +>sign : () => void + + exportKey() { return true } +>exportKey : () => boolean +>true : true + } + } + } + } + // ok + if (chrome.platformKeys.subtleCrypto().exportKey) { +>chrome.platformKeys.subtleCrypto().exportKey : () => boolean +>chrome.platformKeys.subtleCrypto() : { sign(): void; exportKey(): boolean; } +>chrome.platformKeys.subtleCrypto : () => { sign(): void; exportKey(): boolean; } +>chrome.platformKeys : { subtleCrypto(): { sign(): void; exportKey(): boolean; }; } +>chrome : { platformKeys: { subtleCrypto(): { sign(): void; exportKey(): boolean; }; }; } +>platformKeys : { subtleCrypto(): { sign(): void; exportKey(): boolean; }; } +>subtleCrypto : () => { sign(): void; exportKey(): boolean; } +>exportKey : () => boolean + + chrome.platformKeys.subtleCrypto().exportKey +>chrome.platformKeys.subtleCrypto().exportKey : () => boolean +>chrome.platformKeys.subtleCrypto() : { sign(): void; exportKey(): boolean; } +>chrome.platformKeys.subtleCrypto : () => { sign(): void; exportKey(): boolean; } +>chrome.platformKeys : { subtleCrypto(): { sign(): void; exportKey(): boolean; }; } +>chrome : { platformKeys: { subtleCrypto(): { sign(): void; exportKey(): boolean; }; }; } +>platformKeys : { subtleCrypto(): { sign(): void; exportKey(): boolean; }; } +>subtleCrypto : () => { sign(): void; exportKey(): boolean; } +>exportKey : () => boolean + } } class Foo { diff --git a/tests/baselines/reference/truthinessCallExpressionCoercion2.errors.txt b/tests/baselines/reference/truthinessCallExpressionCoercion2.errors.txt index e3d82f1c01986..8ad21267ae708 100644 --- a/tests/baselines/reference/truthinessCallExpressionCoercion2.errors.txt +++ b/tests/baselines/reference/truthinessCallExpressionCoercion2.errors.txt @@ -1,15 +1,16 @@ tests/cases/compiler/truthinessCallExpressionCoercion2.ts(11,5): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead? tests/cases/compiler/truthinessCallExpressionCoercion2.ts(14,10): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead? tests/cases/compiler/truthinessCallExpressionCoercion2.ts(41,18): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead? -tests/cases/compiler/truthinessCallExpressionCoercion2.ts(47,46): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead? -tests/cases/compiler/truthinessCallExpressionCoercion2.ts(58,5): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead? -tests/cases/compiler/truthinessCallExpressionCoercion2.ts(61,10): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead? -tests/cases/compiler/truthinessCallExpressionCoercion2.ts(81,5): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead? -tests/cases/compiler/truthinessCallExpressionCoercion2.ts(91,9): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead? -tests/cases/compiler/truthinessCallExpressionCoercion2.ts(94,14): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead? +tests/cases/compiler/truthinessCallExpressionCoercion2.ts(44,9): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead? +tests/cases/compiler/truthinessCallExpressionCoercion2.ts(55,46): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead? +tests/cases/compiler/truthinessCallExpressionCoercion2.ts(66,5): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead? +tests/cases/compiler/truthinessCallExpressionCoercion2.ts(69,10): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead? +tests/cases/compiler/truthinessCallExpressionCoercion2.ts(89,5): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead? +tests/cases/compiler/truthinessCallExpressionCoercion2.ts(99,9): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead? +tests/cases/compiler/truthinessCallExpressionCoercion2.ts(102,14): error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead? -==== tests/cases/compiler/truthinessCallExpressionCoercion2.ts (9 errors) ==== +==== tests/cases/compiler/truthinessCallExpressionCoercion2.ts (10 errors) ==== declare class A { static from(): string; } @@ -18,7 +19,7 @@ tests/cases/compiler/truthinessCallExpressionCoercion2.ts(94,14): error TS2774: static from(): string; } - function test(required1: () => boolean, required2: () => boolean, optional?: () => boolean) { + function test(required1: () => boolean, required2: () => boolean, b: boolean, optional?: () => boolean) { // error required1 && console.log('required'); ~~~~~~~~~ @@ -57,6 +58,16 @@ tests/cases/compiler/truthinessCallExpressionCoercion2.ts(94,14): error TS2774: required1 && required2 && required1() && console.log('foo'); ~~~~~~~~~ !!! error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead? + + // error + if (required1 && b) { + ~~~~~~~~~ +!!! error TS2774: This condition will always return true since the function is always defined. Did you mean to call it instead? + } + // ok + if (required1 && b) { + required1() + } } function checksConsole() { diff --git a/tests/baselines/reference/truthinessCallExpressionCoercion2.js b/tests/baselines/reference/truthinessCallExpressionCoercion2.js index 998480e3d73f8..04c604feb692f 100644 --- a/tests/baselines/reference/truthinessCallExpressionCoercion2.js +++ b/tests/baselines/reference/truthinessCallExpressionCoercion2.js @@ -7,7 +7,7 @@ declare class B { static from(): string; } -function test(required1: () => boolean, required2: () => boolean, optional?: () => boolean) { +function test(required1: () => boolean, required2: () => boolean, b: boolean, optional?: () => boolean) { // error required1 && console.log('required'); @@ -40,6 +40,14 @@ function test(required1: () => boolean, required2: () => boolean, optional?: () // error required1 && required2 && required1() && console.log('foo'); + + // error + if (required1 && b) { + } + // ok + if (required1 && b) { + required1() + } } function checksConsole() { @@ -107,7 +115,7 @@ class Foo { //// [truthinessCallExpressionCoercion2.js] -function test(required1, required2, optional) { +function test(required1, required2, b, optional) { // error required1 && console.log('required'); // error @@ -130,6 +138,13 @@ function test(required1, required2, optional) { [].forEach(function (f) { return f && f.apply(parent, []); }); // error required1 && required2 && required1() && console.log('foo'); + // error + if (required1 && b) { + } + // ok + if (required1 && b) { + required1(); + } } function checksConsole() { // error diff --git a/tests/baselines/reference/truthinessCallExpressionCoercion2.symbols b/tests/baselines/reference/truthinessCallExpressionCoercion2.symbols index 3120b1322be3a..0101de6584da4 100644 --- a/tests/baselines/reference/truthinessCallExpressionCoercion2.symbols +++ b/tests/baselines/reference/truthinessCallExpressionCoercion2.symbols @@ -13,11 +13,12 @@ declare class B { >from : Symbol(B.from, Decl(truthinessCallExpressionCoercion2.ts, 4, 17)) } -function test(required1: () => boolean, required2: () => boolean, optional?: () => boolean) { +function test(required1: () => boolean, required2: () => boolean, b: boolean, optional?: () => boolean) { >test : Symbol(test, Decl(truthinessCallExpressionCoercion2.ts, 6, 1)) >required1 : Symbol(required1, Decl(truthinessCallExpressionCoercion2.ts, 8, 14)) >required2 : Symbol(required2, Decl(truthinessCallExpressionCoercion2.ts, 8, 39)) ->optional : Symbol(optional, Decl(truthinessCallExpressionCoercion2.ts, 8, 65)) +>b : Symbol(b, Decl(truthinessCallExpressionCoercion2.ts, 8, 65)) +>optional : Symbol(optional, Decl(truthinessCallExpressionCoercion2.ts, 8, 77)) // error required1 && console.log('required'); @@ -45,14 +46,14 @@ function test(required1: () => boolean, required2: () => boolean, optional?: () // ok optional && console.log('optional'); ->optional : Symbol(optional, Decl(truthinessCallExpressionCoercion2.ts, 8, 65)) +>optional : Symbol(optional, Decl(truthinessCallExpressionCoercion2.ts, 8, 77)) >console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) >console : Symbol(console, Decl(lib.dom.d.ts, --, --)) >log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) // ok 1 && optional && console.log('optional'); ->optional : Symbol(optional, Decl(truthinessCallExpressionCoercion2.ts, 8, 65)) +>optional : Symbol(optional, Decl(truthinessCallExpressionCoercion2.ts, 8, 77)) >console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) >console : Symbol(console, Decl(lib.dom.d.ts, --, --)) >log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) @@ -97,10 +98,24 @@ function test(required1: () => boolean, required2: () => boolean, optional?: () >console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) >console : Symbol(console, Decl(lib.dom.d.ts, --, --)) >log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) + + // error + if (required1 && b) { +>required1 : Symbol(required1, Decl(truthinessCallExpressionCoercion2.ts, 8, 14)) +>b : Symbol(b, Decl(truthinessCallExpressionCoercion2.ts, 8, 65)) + } + // ok + if (required1 && b) { +>required1 : Symbol(required1, Decl(truthinessCallExpressionCoercion2.ts, 8, 14)) +>b : Symbol(b, Decl(truthinessCallExpressionCoercion2.ts, 8, 65)) + + required1() +>required1 : Symbol(required1, Decl(truthinessCallExpressionCoercion2.ts, 8, 14)) + } } function checksConsole() { ->checksConsole : Symbol(checksConsole, Decl(truthinessCallExpressionCoercion2.ts, 41, 1)) +>checksConsole : Symbol(checksConsole, Decl(truthinessCallExpressionCoercion2.ts, 49, 1)) // error typeof window !== 'undefined' && window.console && @@ -126,70 +141,70 @@ function checksConsole() { } function checksPropertyAccess() { ->checksPropertyAccess : Symbol(checksPropertyAccess, Decl(truthinessCallExpressionCoercion2.ts, 47, 1)) +>checksPropertyAccess : Symbol(checksPropertyAccess, Decl(truthinessCallExpressionCoercion2.ts, 55, 1)) const x = { ->x : Symbol(x, Decl(truthinessCallExpressionCoercion2.ts, 50, 9)) +>x : Symbol(x, Decl(truthinessCallExpressionCoercion2.ts, 58, 9)) foo: { ->foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 50, 15)) +>foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 58, 15)) bar() { return true; } ->bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 51, 14)) +>bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 59, 14)) } } // error x.foo.bar && console.log('x.foo.bar'); ->x.foo.bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 51, 14)) ->x.foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 50, 15)) ->x : Symbol(x, Decl(truthinessCallExpressionCoercion2.ts, 50, 9)) ->foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 50, 15)) ->bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 51, 14)) +>x.foo.bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 59, 14)) +>x.foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 58, 15)) +>x : Symbol(x, Decl(truthinessCallExpressionCoercion2.ts, 58, 9)) +>foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 58, 15)) +>bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 59, 14)) >console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) >console : Symbol(console, Decl(lib.dom.d.ts, --, --)) >log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) // error 1 && x.foo.bar && console.log('x.foo.bar'); ->x.foo.bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 51, 14)) ->x.foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 50, 15)) ->x : Symbol(x, Decl(truthinessCallExpressionCoercion2.ts, 50, 9)) ->foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 50, 15)) ->bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 51, 14)) +>x.foo.bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 59, 14)) +>x.foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 58, 15)) +>x : Symbol(x, Decl(truthinessCallExpressionCoercion2.ts, 58, 9)) +>foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 58, 15)) +>bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 59, 14)) >console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) >console : Symbol(console, Decl(lib.dom.d.ts, --, --)) >log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) // ok x.foo.bar && x.foo.bar(); ->x.foo.bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 51, 14)) ->x.foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 50, 15)) ->x : Symbol(x, Decl(truthinessCallExpressionCoercion2.ts, 50, 9)) ->foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 50, 15)) ->bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 51, 14)) ->x.foo.bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 51, 14)) ->x.foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 50, 15)) ->x : Symbol(x, Decl(truthinessCallExpressionCoercion2.ts, 50, 9)) ->foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 50, 15)) ->bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 51, 14)) +>x.foo.bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 59, 14)) +>x.foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 58, 15)) +>x : Symbol(x, Decl(truthinessCallExpressionCoercion2.ts, 58, 9)) +>foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 58, 15)) +>bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 59, 14)) +>x.foo.bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 59, 14)) +>x.foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 58, 15)) +>x : Symbol(x, Decl(truthinessCallExpressionCoercion2.ts, 58, 9)) +>foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 58, 15)) +>bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 59, 14)) // ok x.foo.bar && 1 && x.foo.bar(); ->x.foo.bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 51, 14)) ->x.foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 50, 15)) ->x : Symbol(x, Decl(truthinessCallExpressionCoercion2.ts, 50, 9)) ->foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 50, 15)) ->bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 51, 14)) ->x.foo.bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 51, 14)) ->x.foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 50, 15)) ->x : Symbol(x, Decl(truthinessCallExpressionCoercion2.ts, 50, 9)) ->foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 50, 15)) ->bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 51, 14)) +>x.foo.bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 59, 14)) +>x.foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 58, 15)) +>x : Symbol(x, Decl(truthinessCallExpressionCoercion2.ts, 58, 9)) +>foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 58, 15)) +>bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 59, 14)) +>x.foo.bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 59, 14)) +>x.foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 58, 15)) +>x : Symbol(x, Decl(truthinessCallExpressionCoercion2.ts, 58, 9)) +>foo : Symbol(foo, Decl(truthinessCallExpressionCoercion2.ts, 58, 15)) +>bar : Symbol(bar, Decl(truthinessCallExpressionCoercion2.ts, 59, 14)) // ok const y = A.from && (A.from as Function) !== B.from ? true : false; ->y : Symbol(y, Decl(truthinessCallExpressionCoercion2.ts, 69, 9)) +>y : Symbol(y, Decl(truthinessCallExpressionCoercion2.ts, 77, 9)) >A.from : Symbol(A.from, Decl(truthinessCallExpressionCoercion2.ts, 0, 17)) >A : Symbol(A, Decl(truthinessCallExpressionCoercion2.ts, 0, 0)) >from : Symbol(A.from, Decl(truthinessCallExpressionCoercion2.ts, 0, 17)) @@ -202,98 +217,98 @@ function checksPropertyAccess() { >from : Symbol(B.from, Decl(truthinessCallExpressionCoercion2.ts, 4, 17)) y; ->y : Symbol(y, Decl(truthinessCallExpressionCoercion2.ts, 69, 9)) +>y : Symbol(y, Decl(truthinessCallExpressionCoercion2.ts, 77, 9)) const x1 = { ->x1 : Symbol(x1, Decl(truthinessCallExpressionCoercion2.ts, 72, 9)) +>x1 : Symbol(x1, Decl(truthinessCallExpressionCoercion2.ts, 80, 9)) a: { b: { c: () => {} } } ->a : Symbol(a, Decl(truthinessCallExpressionCoercion2.ts, 72, 16)) ->b : Symbol(b, Decl(truthinessCallExpressionCoercion2.ts, 73, 12)) ->c : Symbol(c, Decl(truthinessCallExpressionCoercion2.ts, 73, 17)) +>a : Symbol(a, Decl(truthinessCallExpressionCoercion2.ts, 80, 16)) +>b : Symbol(b, Decl(truthinessCallExpressionCoercion2.ts, 81, 12)) +>c : Symbol(c, Decl(truthinessCallExpressionCoercion2.ts, 81, 17)) } const x2 = { ->x2 : Symbol(x2, Decl(truthinessCallExpressionCoercion2.ts, 75, 9)) +>x2 : Symbol(x2, Decl(truthinessCallExpressionCoercion2.ts, 83, 9)) a: { b: { c: () => {} } } ->a : Symbol(a, Decl(truthinessCallExpressionCoercion2.ts, 75, 16)) ->b : Symbol(b, Decl(truthinessCallExpressionCoercion2.ts, 76, 12)) ->c : Symbol(c, Decl(truthinessCallExpressionCoercion2.ts, 76, 17)) +>a : Symbol(a, Decl(truthinessCallExpressionCoercion2.ts, 83, 16)) +>b : Symbol(b, Decl(truthinessCallExpressionCoercion2.ts, 84, 12)) +>c : Symbol(c, Decl(truthinessCallExpressionCoercion2.ts, 84, 17)) } // error x1.a.b.c && x2.a.b.c(); ->x1.a.b.c : Symbol(c, Decl(truthinessCallExpressionCoercion2.ts, 73, 17)) ->x1.a.b : Symbol(b, Decl(truthinessCallExpressionCoercion2.ts, 73, 12)) ->x1.a : Symbol(a, Decl(truthinessCallExpressionCoercion2.ts, 72, 16)) ->x1 : Symbol(x1, Decl(truthinessCallExpressionCoercion2.ts, 72, 9)) ->a : Symbol(a, Decl(truthinessCallExpressionCoercion2.ts, 72, 16)) ->b : Symbol(b, Decl(truthinessCallExpressionCoercion2.ts, 73, 12)) ->c : Symbol(c, Decl(truthinessCallExpressionCoercion2.ts, 73, 17)) ->x2.a.b.c : Symbol(c, Decl(truthinessCallExpressionCoercion2.ts, 76, 17)) ->x2.a.b : Symbol(b, Decl(truthinessCallExpressionCoercion2.ts, 76, 12)) ->x2.a : Symbol(a, Decl(truthinessCallExpressionCoercion2.ts, 75, 16)) ->x2 : Symbol(x2, Decl(truthinessCallExpressionCoercion2.ts, 75, 9)) ->a : Symbol(a, Decl(truthinessCallExpressionCoercion2.ts, 75, 16)) ->b : Symbol(b, Decl(truthinessCallExpressionCoercion2.ts, 76, 12)) ->c : Symbol(c, Decl(truthinessCallExpressionCoercion2.ts, 76, 17)) +>x1.a.b.c : Symbol(c, Decl(truthinessCallExpressionCoercion2.ts, 81, 17)) +>x1.a.b : Symbol(b, Decl(truthinessCallExpressionCoercion2.ts, 81, 12)) +>x1.a : Symbol(a, Decl(truthinessCallExpressionCoercion2.ts, 80, 16)) +>x1 : Symbol(x1, Decl(truthinessCallExpressionCoercion2.ts, 80, 9)) +>a : Symbol(a, Decl(truthinessCallExpressionCoercion2.ts, 80, 16)) +>b : Symbol(b, Decl(truthinessCallExpressionCoercion2.ts, 81, 12)) +>c : Symbol(c, Decl(truthinessCallExpressionCoercion2.ts, 81, 17)) +>x2.a.b.c : Symbol(c, Decl(truthinessCallExpressionCoercion2.ts, 84, 17)) +>x2.a.b : Symbol(b, Decl(truthinessCallExpressionCoercion2.ts, 84, 12)) +>x2.a : Symbol(a, Decl(truthinessCallExpressionCoercion2.ts, 83, 16)) +>x2 : Symbol(x2, Decl(truthinessCallExpressionCoercion2.ts, 83, 9)) +>a : Symbol(a, Decl(truthinessCallExpressionCoercion2.ts, 83, 16)) +>b : Symbol(b, Decl(truthinessCallExpressionCoercion2.ts, 84, 12)) +>c : Symbol(c, Decl(truthinessCallExpressionCoercion2.ts, 84, 17)) } class Foo { ->Foo : Symbol(Foo, Decl(truthinessCallExpressionCoercion2.ts, 81, 1)) +>Foo : Symbol(Foo, Decl(truthinessCallExpressionCoercion2.ts, 89, 1)) optional?: () => boolean; ->optional : Symbol(Foo.optional, Decl(truthinessCallExpressionCoercion2.ts, 83, 11)) +>optional : Symbol(Foo.optional, Decl(truthinessCallExpressionCoercion2.ts, 91, 11)) required() { ->required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 84, 29)) +>required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 92, 29)) return true; } test() { ->test : Symbol(Foo.test, Decl(truthinessCallExpressionCoercion2.ts, 87, 5)) +>test : Symbol(Foo.test, Decl(truthinessCallExpressionCoercion2.ts, 95, 5)) // error this.required && console.log('required'); ->this.required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 84, 29)) ->this : Symbol(Foo, Decl(truthinessCallExpressionCoercion2.ts, 81, 1)) ->required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 84, 29)) +>this.required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 92, 29)) +>this : Symbol(Foo, Decl(truthinessCallExpressionCoercion2.ts, 89, 1)) +>required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 92, 29)) >console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) >console : Symbol(console, Decl(lib.dom.d.ts, --, --)) >log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) // error 1 && this.required && console.log('required'); ->this.required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 84, 29)) ->this : Symbol(Foo, Decl(truthinessCallExpressionCoercion2.ts, 81, 1)) ->required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 84, 29)) +>this.required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 92, 29)) +>this : Symbol(Foo, Decl(truthinessCallExpressionCoercion2.ts, 89, 1)) +>required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 92, 29)) >console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) >console : Symbol(console, Decl(lib.dom.d.ts, --, --)) >log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) // ok this.required && this.required(); ->this.required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 84, 29)) ->this : Symbol(Foo, Decl(truthinessCallExpressionCoercion2.ts, 81, 1)) ->required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 84, 29)) ->this.required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 84, 29)) ->this : Symbol(Foo, Decl(truthinessCallExpressionCoercion2.ts, 81, 1)) ->required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 84, 29)) +>this.required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 92, 29)) +>this : Symbol(Foo, Decl(truthinessCallExpressionCoercion2.ts, 89, 1)) +>required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 92, 29)) +>this.required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 92, 29)) +>this : Symbol(Foo, Decl(truthinessCallExpressionCoercion2.ts, 89, 1)) +>required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 92, 29)) // ok this.required && 1 && this.required(); ->this.required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 84, 29)) ->this : Symbol(Foo, Decl(truthinessCallExpressionCoercion2.ts, 81, 1)) ->required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 84, 29)) ->this.required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 84, 29)) ->this : Symbol(Foo, Decl(truthinessCallExpressionCoercion2.ts, 81, 1)) ->required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 84, 29)) +>this.required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 92, 29)) +>this : Symbol(Foo, Decl(truthinessCallExpressionCoercion2.ts, 89, 1)) +>required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 92, 29)) +>this.required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 92, 29)) +>this : Symbol(Foo, Decl(truthinessCallExpressionCoercion2.ts, 89, 1)) +>required : Symbol(Foo.required, Decl(truthinessCallExpressionCoercion2.ts, 92, 29)) // ok 1 && this.optional && console.log('optional'); ->this.optional : Symbol(Foo.optional, Decl(truthinessCallExpressionCoercion2.ts, 83, 11)) ->this : Symbol(Foo, Decl(truthinessCallExpressionCoercion2.ts, 81, 1)) ->optional : Symbol(Foo.optional, Decl(truthinessCallExpressionCoercion2.ts, 83, 11)) +>this.optional : Symbol(Foo.optional, Decl(truthinessCallExpressionCoercion2.ts, 91, 11)) +>this : Symbol(Foo, Decl(truthinessCallExpressionCoercion2.ts, 89, 1)) +>optional : Symbol(Foo.optional, Decl(truthinessCallExpressionCoercion2.ts, 91, 11)) >console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) >console : Symbol(console, Decl(lib.dom.d.ts, --, --)) >log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) diff --git a/tests/baselines/reference/truthinessCallExpressionCoercion2.types b/tests/baselines/reference/truthinessCallExpressionCoercion2.types index bf3b9ab91ab86..31004053e66ea 100644 --- a/tests/baselines/reference/truthinessCallExpressionCoercion2.types +++ b/tests/baselines/reference/truthinessCallExpressionCoercion2.types @@ -13,10 +13,11 @@ declare class B { >from : () => string } -function test(required1: () => boolean, required2: () => boolean, optional?: () => boolean) { ->test : (required1: () => boolean, required2: () => boolean, optional?: (() => boolean) | undefined) => void +function test(required1: () => boolean, required2: () => boolean, b: boolean, optional?: () => boolean) { +>test : (required1: () => boolean, required2: () => boolean, b: boolean, optional?: (() => boolean) | undefined) => void >required1 : () => boolean >required2 : () => boolean +>b : boolean >optional : (() => boolean) | undefined // error @@ -145,6 +146,23 @@ function test(required1: () => boolean, required2: () => boolean, optional?: () >console : Console >log : (...data: any[]) => void >'foo' : "foo" + + // error + if (required1 && b) { +>required1 && b : boolean +>required1 : () => boolean +>b : boolean + } + // ok + if (required1 && b) { +>required1 && b : boolean +>required1 : () => boolean +>b : boolean + + required1() +>required1() : boolean +>required1 : () => boolean + } } function checksConsole() { diff --git a/tests/cases/compiler/truthinessCallExpressionCoercion1.ts b/tests/cases/compiler/truthinessCallExpressionCoercion1.ts index 6835a434aa452..fef57a042cf30 100644 --- a/tests/cases/compiler/truthinessCallExpressionCoercion1.ts +++ b/tests/cases/compiler/truthinessCallExpressionCoercion1.ts @@ -49,6 +49,21 @@ function checksPropertyAccess() { // ok x.foo.bar ? x.foo.bar : undefined; + + var chrome = { + platformKeys: { + subtleCrypto() { + return { + sign() {}, + exportKey() { return true } + } + } + } + } + // ok + if (chrome.platformKeys.subtleCrypto().exportKey) { + chrome.platformKeys.subtleCrypto().exportKey + } } class Foo { diff --git a/tests/cases/compiler/truthinessCallExpressionCoercion2.ts b/tests/cases/compiler/truthinessCallExpressionCoercion2.ts index b313aa8330436..a29c346cf6291 100644 --- a/tests/cases/compiler/truthinessCallExpressionCoercion2.ts +++ b/tests/cases/compiler/truthinessCallExpressionCoercion2.ts @@ -9,7 +9,7 @@ declare class B { static from(): string; } -function test(required1: () => boolean, required2: () => boolean, optional?: () => boolean) { +function test(required1: () => boolean, required2: () => boolean, b: boolean, optional?: () => boolean) { // error required1 && console.log('required'); @@ -42,6 +42,14 @@ function test(required1: () => boolean, required2: () => boolean, optional?: () // error required1 && required2 && required1() && console.log('foo'); + + // error + if (required1 && b) { + } + // ok + if (required1 && b) { + required1() + } } function checksConsole() {