From a594c6aa4966cf537aa7d866b14a050e2c7745cf Mon Sep 17 00:00:00 2001 From: JoostK Date: Tue, 12 Jul 2022 18:27:40 +0200 Subject: [PATCH] Reuse computed type of condition expressions --- src/compiler/checker.ts | 15 ++-- ...uncalledFunctionChecksInConditionalPerf.js | 8 +++ ...ledFunctionChecksInConditionalPerf.symbols | 28 ++++++++ ...alledFunctionChecksInConditionalPerf.types | 71 +++++++++++++++++++ ...uncalledFunctionChecksInConditionalPerf.ts | 5 ++ 5 files changed, 120 insertions(+), 7 deletions(-) create mode 100644 tests/baselines/reference/uncalledFunctionChecksInConditionalPerf.js create mode 100644 tests/baselines/reference/uncalledFunctionChecksInConditionalPerf.symbols create mode 100644 tests/baselines/reference/uncalledFunctionChecksInConditionalPerf.types create mode 100644 tests/cases/compiler/uncalledFunctionChecksInConditionalPerf.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ebe2d1c84b566..a6451fb233d73 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -33920,7 +33920,7 @@ namespace ts { if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken || operator === SyntaxKind.QuestionQuestionToken) { if (operator === SyntaxKind.AmpersandAmpersandToken) { const parent = walkUpParenthesizedExpressions(node.parent); - checkTestingKnownTruthyCallableOrAwaitableType(node.left, isIfStatement(parent) ? parent.thenStatement : undefined); + checkTestingKnownTruthyCallableOrAwaitableType(node.left, leftType, isIfStatement(parent) ? parent.thenStatement : undefined); } checkTruthinessOfType(leftType, node.left); } @@ -34504,8 +34504,8 @@ namespace ts { } function checkConditionalExpression(node: ConditionalExpression, checkMode?: CheckMode): Type { - checkTruthinessExpression(node.condition); - checkTestingKnownTruthyCallableOrAwaitableType(node.condition, node.whenTrue); + const type = checkTruthinessExpression(node.condition); + checkTestingKnownTruthyCallableOrAwaitableType(node.condition, type, node.whenTrue); const type1 = checkExpression(node.whenTrue, checkMode); const type2 = checkExpression(node.whenFalse, checkMode); return getUnionType([type1, type2], UnionReduction.Subtype); @@ -38206,8 +38206,8 @@ namespace ts { function checkIfStatement(node: IfStatement) { // Grammar checking checkGrammarStatementInAmbientContext(node); - checkTruthinessExpression(node.expression); - checkTestingKnownTruthyCallableOrAwaitableType(node.expression, node.thenStatement); + const type = checkTruthinessExpression(node.expression); + checkTestingKnownTruthyCallableOrAwaitableType(node.expression, type, node.thenStatement); checkSourceElement(node.thenStatement); if (node.thenStatement.kind === SyntaxKind.EmptyStatement) { @@ -38217,8 +38217,9 @@ namespace ts { checkSourceElement(node.elseStatement); } - function checkTestingKnownTruthyCallableOrAwaitableType(condExpr: Expression, body?: Statement | Expression) { + function checkTestingKnownTruthyCallableOrAwaitableType(condExpr: Expression, condType: Type, body?: Statement | Expression) { if (!strictNullChecks) return; + if (!(getTypeFacts(condType) & TypeFacts.Truthy)) return; helper(condExpr, body); while (isBinaryExpression(condExpr) && condExpr.operatorToken.kind === SyntaxKind.BarBarToken) { @@ -38232,7 +38233,7 @@ namespace ts { ? condExpr.right : condExpr; if (isModuleExportsAccessExpression(location)) return; - const type = checkTruthinessExpression(location); + const type = location === condExpr ? condType : checkTruthinessExpression(location); const isPropertyExpressionCast = isPropertyAccessExpression(location) && isTypeAssertion(location.expression); if (!(getTypeFacts(type) & TypeFacts.Truthy) || isPropertyExpressionCast) return; diff --git a/tests/baselines/reference/uncalledFunctionChecksInConditionalPerf.js b/tests/baselines/reference/uncalledFunctionChecksInConditionalPerf.js new file mode 100644 index 0000000000000..0a80b4dedfc16 --- /dev/null +++ b/tests/baselines/reference/uncalledFunctionChecksInConditionalPerf.js @@ -0,0 +1,8 @@ +//// [uncalledFunctionChecksInConditionalPerf.ts] +declare const b: boolean; + +((((((((((((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b); + + +//// [uncalledFunctionChecksInConditionalPerf.js] +((((((((((((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b); diff --git a/tests/baselines/reference/uncalledFunctionChecksInConditionalPerf.symbols b/tests/baselines/reference/uncalledFunctionChecksInConditionalPerf.symbols new file mode 100644 index 0000000000000..094a446b04a44 --- /dev/null +++ b/tests/baselines/reference/uncalledFunctionChecksInConditionalPerf.symbols @@ -0,0 +1,28 @@ +=== tests/cases/compiler/uncalledFunctionChecksInConditionalPerf.ts === +declare const b: boolean; +>b : Symbol(b, Decl(uncalledFunctionChecksInConditionalPerf.ts, 0, 13)) + +((((((((((((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b); +>b : Symbol(b, Decl(uncalledFunctionChecksInConditionalPerf.ts, 0, 13)) +>b : Symbol(b, Decl(uncalledFunctionChecksInConditionalPerf.ts, 0, 13)) +>b : Symbol(b, Decl(uncalledFunctionChecksInConditionalPerf.ts, 0, 13)) +>b : Symbol(b, Decl(uncalledFunctionChecksInConditionalPerf.ts, 0, 13)) +>b : Symbol(b, Decl(uncalledFunctionChecksInConditionalPerf.ts, 0, 13)) +>b : Symbol(b, Decl(uncalledFunctionChecksInConditionalPerf.ts, 0, 13)) +>b : Symbol(b, Decl(uncalledFunctionChecksInConditionalPerf.ts, 0, 13)) +>b : Symbol(b, Decl(uncalledFunctionChecksInConditionalPerf.ts, 0, 13)) +>b : Symbol(b, Decl(uncalledFunctionChecksInConditionalPerf.ts, 0, 13)) +>b : Symbol(b, Decl(uncalledFunctionChecksInConditionalPerf.ts, 0, 13)) +>b : Symbol(b, Decl(uncalledFunctionChecksInConditionalPerf.ts, 0, 13)) +>b : Symbol(b, Decl(uncalledFunctionChecksInConditionalPerf.ts, 0, 13)) +>b : Symbol(b, Decl(uncalledFunctionChecksInConditionalPerf.ts, 0, 13)) +>b : Symbol(b, Decl(uncalledFunctionChecksInConditionalPerf.ts, 0, 13)) +>b : Symbol(b, Decl(uncalledFunctionChecksInConditionalPerf.ts, 0, 13)) +>b : Symbol(b, Decl(uncalledFunctionChecksInConditionalPerf.ts, 0, 13)) +>b : Symbol(b, Decl(uncalledFunctionChecksInConditionalPerf.ts, 0, 13)) +>b : Symbol(b, Decl(uncalledFunctionChecksInConditionalPerf.ts, 0, 13)) +>b : Symbol(b, Decl(uncalledFunctionChecksInConditionalPerf.ts, 0, 13)) +>b : Symbol(b, Decl(uncalledFunctionChecksInConditionalPerf.ts, 0, 13)) +>b : Symbol(b, Decl(uncalledFunctionChecksInConditionalPerf.ts, 0, 13)) +>b : Symbol(b, Decl(uncalledFunctionChecksInConditionalPerf.ts, 0, 13)) + diff --git a/tests/baselines/reference/uncalledFunctionChecksInConditionalPerf.types b/tests/baselines/reference/uncalledFunctionChecksInConditionalPerf.types new file mode 100644 index 0000000000000..533fda8569bcb --- /dev/null +++ b/tests/baselines/reference/uncalledFunctionChecksInConditionalPerf.types @@ -0,0 +1,71 @@ +=== tests/cases/compiler/uncalledFunctionChecksInConditionalPerf.ts === +declare const b: boolean; +>b : boolean + +((((((((((((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b); +>((((((((((((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) : boolean +>(((((((((((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b : boolean +>(((((((((((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) : boolean +>((((((((((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b : boolean +>((((((((((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) : boolean +>(((((((((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b : boolean +>(((((((((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) : boolean +>((((((((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b : boolean +>((((((((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) : boolean +>(((((((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b : boolean +>(((((((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) : boolean +>((((((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b : boolean +>((((((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) : boolean +>(((((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b : boolean +>(((((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) : boolean +>((((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b : boolean +>((((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) : boolean +>(((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b : boolean +>(((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) : boolean +>((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b : boolean +>((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) : boolean +>(((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b : boolean +>(((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) : boolean +>((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b : boolean +>((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) : boolean +>(((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b : boolean +>(((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) : boolean +>((((((((b) && b) && b) && b) && b) && b) && b) && b) && b : boolean +>((((((((b) && b) && b) && b) && b) && b) && b) && b) : boolean +>(((((((b) && b) && b) && b) && b) && b) && b) && b : boolean +>(((((((b) && b) && b) && b) && b) && b) && b) : boolean +>((((((b) && b) && b) && b) && b) && b) && b : boolean +>((((((b) && b) && b) && b) && b) && b) : boolean +>(((((b) && b) && b) && b) && b) && b : boolean +>(((((b) && b) && b) && b) && b) : boolean +>((((b) && b) && b) && b) && b : boolean +>((((b) && b) && b) && b) : boolean +>(((b) && b) && b) && b : boolean +>(((b) && b) && b) : boolean +>((b) && b) && b : boolean +>((b) && b) : boolean +>(b) && b : boolean +>(b) : boolean +>b : boolean +>b : true +>b : true +>b : true +>b : true +>b : true +>b : true +>b : true +>b : true +>b : true +>b : true +>b : true +>b : true +>b : true +>b : true +>b : true +>b : true +>b : true +>b : true +>b : true +>b : true +>b : true + diff --git a/tests/cases/compiler/uncalledFunctionChecksInConditionalPerf.ts b/tests/cases/compiler/uncalledFunctionChecksInConditionalPerf.ts new file mode 100644 index 0000000000000..57e74a44b5400 --- /dev/null +++ b/tests/cases/compiler/uncalledFunctionChecksInConditionalPerf.ts @@ -0,0 +1,5 @@ +// @strictNullChecks: true + +declare const b: boolean; + +((((((((((((((((((((((b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b) && b);