Cherry-pick PR #34702 into release-3.7 (#34710)

Component commits:
7be925173c Exclude ?? operator from true/false literal check in createFlowCondition

b9802166ae Accept new API baselines

3d4c14c5f8 Add tests

7362545e8c Accept new baselines

2d1af77839 Address CR feedback

8f0de27784 Accept new API baselines
This commit is contained in:
TypeScript Bot 2019-10-24 16:05:34 -07:00 committed by Daniel Rosenwasser
parent db419ff5ab
commit 330c8acda2
8 changed files with 166 additions and 7 deletions

View File

@ -1,3 +1,4 @@
/* @internal */
namespace ts {
export const enum ModuleInstanceState {
@ -951,11 +952,10 @@ namespace ts {
if (!expression) {
return flags & FlowFlags.TrueCondition ? antecedent : unreachableFlow;
}
if (expression.kind === SyntaxKind.TrueKeyword && flags & FlowFlags.FalseCondition ||
expression.kind === SyntaxKind.FalseKeyword && flags & FlowFlags.TrueCondition) {
if (!isExpressionOfOptionalChainRoot(expression)) {
return unreachableFlow;
}
if ((expression.kind === SyntaxKind.TrueKeyword && flags & FlowFlags.FalseCondition ||
expression.kind === SyntaxKind.FalseKeyword && flags & FlowFlags.TrueCondition) &&
!isExpressionOfOptionalChainRoot(expression) && !isNullishCoalesce(expression.parent)) {
return unreachableFlow;
}
if (!isNarrowingExpression(expression)) {
return antecedent;

View File

@ -5925,6 +5925,10 @@ namespace ts {
return isOptionalChainRoot(node.parent) && node.parent.expression === node;
}
export function isNullishCoalesce(node: Node) {
return node.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>node).operatorToken.kind === SyntaxKind.QuestionQuestionToken;
}
export function isNewExpression(node: Node): node is NewExpression {
return node.kind === SyntaxKind.NewExpression;
}

View File

@ -3525,6 +3525,7 @@ declare namespace ts {
function isCallExpression(node: Node): node is CallExpression;
function isCallChain(node: Node): node is CallChain;
function isOptionalChain(node: Node): node is PropertyAccessChain | ElementAccessChain | CallChain;
function isNullishCoalesce(node: Node): boolean;
function isNewExpression(node: Node): node is NewExpression;
function isTaggedTemplateExpression(node: Node): node is TaggedTemplateExpression;
function isTypeAssertion(node: Node): node is TypeAssertion;

View File

@ -3525,6 +3525,7 @@ declare namespace ts {
function isCallExpression(node: Node): node is CallExpression;
function isCallChain(node: Node): node is CallChain;
function isOptionalChain(node: Node): node is PropertyAccessChain | ElementAccessChain | CallChain;
function isNullishCoalesce(node: Node): boolean;
function isNewExpression(node: Node): node is NewExpression;
function isTaggedTemplateExpression(node: Node): node is TaggedTemplateExpression;
function isTypeAssertion(node: Node): node is TypeAssertion;

View File

@ -38,10 +38,36 @@ const cc4 = c4 ?? true;
const dd1 = d1 ?? {b: 1};
const dd2 = d2 ?? {b: 1};
const dd3 = d3 ?? {b: 1};
const dd4 = d4 ?? {b: 1};
const dd4 = d4 ?? {b: 1};
// Repro from #34635
declare function foo(): void;
const maybeBool = false;
if (!(maybeBool ?? true)) {
foo();
}
if (maybeBool ?? true) {
foo();
}
else {
foo();
}
if (false ?? true) {
foo();
}
else {
foo();
}
//// [nullishCoalescingOperator1.js]
"use strict";
var _a;
var aa1 = (a1 !== null && a1 !== void 0 ? a1 : 'whatever');
var aa2 = (a2 !== null && a2 !== void 0 ? a2 : 'whatever');
var aa3 = (a3 !== null && a3 !== void 0 ? a3 : 'whatever');
@ -58,3 +84,19 @@ var dd1 = (d1 !== null && d1 !== void 0 ? d1 : { b: 1 });
var dd2 = (d2 !== null && d2 !== void 0 ? d2 : { b: 1 });
var dd3 = (d3 !== null && d3 !== void 0 ? d3 : { b: 1 });
var dd4 = (d4 !== null && d4 !== void 0 ? d4 : { b: 1 });
var maybeBool = false;
if (!((maybeBool !== null && maybeBool !== void 0 ? maybeBool : true))) {
foo();
}
if ((maybeBool !== null && maybeBool !== void 0 ? maybeBool : true)) {
foo();
}
else {
foo();
}
if (_a = false, (_a !== null && _a !== void 0 ? _a : true)) {
foo();
}
else {
foo();
}

View File

@ -123,3 +123,38 @@ const dd4 = d4 ?? {b: 1};
>d4 : Symbol(d4, Decl(nullishCoalescingOperator1.ts, 19, 13))
>b : Symbol(b, Decl(nullishCoalescingOperator1.ts, 39, 19))
// Repro from #34635
declare function foo(): void;
>foo : Symbol(foo, Decl(nullishCoalescingOperator1.ts, 39, 25))
const maybeBool = false;
>maybeBool : Symbol(maybeBool, Decl(nullishCoalescingOperator1.ts, 45, 5))
if (!(maybeBool ?? true)) {
>maybeBool : Symbol(maybeBool, Decl(nullishCoalescingOperator1.ts, 45, 5))
foo();
>foo : Symbol(foo, Decl(nullishCoalescingOperator1.ts, 39, 25))
}
if (maybeBool ?? true) {
>maybeBool : Symbol(maybeBool, Decl(nullishCoalescingOperator1.ts, 45, 5))
foo();
>foo : Symbol(foo, Decl(nullishCoalescingOperator1.ts, 39, 25))
}
else {
foo();
>foo : Symbol(foo, Decl(nullishCoalescingOperator1.ts, 39, 25))
}
if (false ?? true) {
foo();
>foo : Symbol(foo, Decl(nullishCoalescingOperator1.ts, 39, 25))
}
else {
foo();
>foo : Symbol(foo, Decl(nullishCoalescingOperator1.ts, 39, 25))
}

View File

@ -170,3 +170,54 @@ const dd4 = d4 ?? {b: 1};
>b : number
>1 : 1
// Repro from #34635
declare function foo(): void;
>foo : () => void
const maybeBool = false;
>maybeBool : false
>false : false
if (!(maybeBool ?? true)) {
>!(maybeBool ?? true) : true
>(maybeBool ?? true) : false
>maybeBool ?? true : false
>maybeBool : false
>true : true
foo();
>foo() : void
>foo : () => void
}
if (maybeBool ?? true) {
>maybeBool ?? true : false
>maybeBool : false
>true : true
foo();
>foo() : void
>foo : () => void
}
else {
foo();
>foo() : void
>foo : () => void
}
if (false ?? true) {
>false ?? true : false
>false : false
>true : true
foo();
>foo() : void
>foo : () => void
}
else {
foo();
>foo() : void
>foo : () => void
}

View File

@ -1,4 +1,5 @@
// @strict: true
// @allowUnreachableCode: false
declare const a1: string | undefined | null
declare const a2: string | undefined | null
@ -39,4 +40,28 @@ const cc4 = c4 ?? true;
const dd1 = d1 ?? {b: 1};
const dd2 = d2 ?? {b: 1};
const dd3 = d3 ?? {b: 1};
const dd4 = d4 ?? {b: 1};
const dd4 = d4 ?? {b: 1};
// Repro from #34635
declare function foo(): void;
const maybeBool = false;
if (!(maybeBool ?? true)) {
foo();
}
if (maybeBool ?? true) {
foo();
}
else {
foo();
}
if (false ?? true) {
foo();
}
else {
foo();
}