mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-29 03:17:51 -05:00
Merge pull request #8286 from Microsoft/controlFlowCacheFix
Control flow cache fix
This commit is contained in:
@@ -645,6 +645,13 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
function createFlowLoopLabel(): FlowLabel {
|
||||
return {
|
||||
kind: FlowKind.LoopLabel,
|
||||
antecedents: undefined
|
||||
};
|
||||
}
|
||||
|
||||
function addAntecedent(label: FlowLabel, antecedent: FlowNode): void {
|
||||
if (antecedent.kind !== FlowKind.Unreachable && !contains(label.antecedents, antecedent)) {
|
||||
(label.antecedents || (label.antecedents = [])).push(antecedent);
|
||||
@@ -755,7 +762,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function bindWhileStatement(node: WhileStatement): void {
|
||||
const preWhileLabel = createFlowLabel();
|
||||
const preWhileLabel = createFlowLoopLabel();
|
||||
const preBodyLabel = createFlowLabel();
|
||||
const postWhileLabel = createFlowLabel();
|
||||
addAntecedent(preWhileLabel, currentFlow);
|
||||
@@ -768,7 +775,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function bindDoStatement(node: DoStatement): void {
|
||||
const preDoLabel = createFlowLabel();
|
||||
const preDoLabel = createFlowLoopLabel();
|
||||
const preConditionLabel = createFlowLabel();
|
||||
const postDoLabel = createFlowLabel();
|
||||
addAntecedent(preDoLabel, currentFlow);
|
||||
@@ -781,7 +788,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function bindForStatement(node: ForStatement): void {
|
||||
const preLoopLabel = createFlowLabel();
|
||||
const preLoopLabel = createFlowLoopLabel();
|
||||
const preBodyLabel = createFlowLabel();
|
||||
const postLoopLabel = createFlowLabel();
|
||||
bind(node.initializer);
|
||||
@@ -796,7 +803,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function bindForInOrForOfStatement(node: ForInStatement | ForOfStatement): void {
|
||||
const preLoopLabel = createFlowLabel();
|
||||
const preLoopLabel = createFlowLoopLabel();
|
||||
const postLoopLabel = createFlowLabel();
|
||||
addAntecedent(preLoopLabel, currentFlow);
|
||||
currentFlow = preLoopLabel;
|
||||
@@ -943,7 +950,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function bindLabeledStatement(node: LabeledStatement): void {
|
||||
const preStatementLabel = createFlowLabel();
|
||||
const preStatementLabel = createFlowLoopLabel();
|
||||
const postStatementLabel = createFlowLabel();
|
||||
bind(node.label);
|
||||
addAntecedent(preStatementLabel, currentFlow);
|
||||
|
||||
@@ -7592,6 +7592,7 @@ namespace ts {
|
||||
case FlowKind.Condition:
|
||||
return getTypeAtFlowCondition(<FlowCondition>flow);
|
||||
case FlowKind.Label:
|
||||
case FlowKind.LoopLabel:
|
||||
if ((<FlowLabel>flow).antecedents.length === 1) {
|
||||
flow = (<FlowLabel>flow).antecedents[0];
|
||||
continue;
|
||||
@@ -7639,7 +7640,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getTypeAtFlowCondition(flow: FlowCondition) {
|
||||
return narrowType(getTypeAtFlowNode(flow.antecedent), flow.expression, flow.assumeTrue);
|
||||
const type = getTypeAtFlowNode(flow.antecedent);
|
||||
return type && narrowType(type, flow.expression, flow.assumeTrue);
|
||||
}
|
||||
|
||||
function getTypeAtFlowNodeCached(flow: FlowNode) {
|
||||
@@ -7665,13 +7667,15 @@ namespace ts {
|
||||
flowStackCount--;
|
||||
// Record the result only if the cache is still empty. If checkExpressionCached was called
|
||||
// during processing it is possible we've already recorded a result.
|
||||
return cache[key] || (cache[key] = type);
|
||||
return cache[key] || type && (cache[key] = type);
|
||||
}
|
||||
|
||||
function getTypeAtFlowLabel(flow: FlowLabel) {
|
||||
const antecedentTypes: Type[] = [];
|
||||
for (const antecedent of flow.antecedents) {
|
||||
const type = getTypeAtFlowNodeCached(antecedent);
|
||||
const type = flow.kind === FlowKind.LoopLabel ?
|
||||
getTypeAtFlowNodeCached(antecedent) :
|
||||
getTypeAtFlowNode(antecedent);
|
||||
if (type) {
|
||||
// If the type at a particular antecedent path is the declared type and the
|
||||
// reference is known to always be assigned (i.e. when declared and initial types
|
||||
@@ -7685,7 +7689,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
return antecedentTypes.length === 0 ? declaredType :
|
||||
return antecedentTypes.length === 0 ? undefined :
|
||||
antecedentTypes.length === 1 ? antecedentTypes[0] :
|
||||
getUnionType(antecedentTypes);
|
||||
}
|
||||
|
||||
@@ -1519,6 +1519,7 @@ namespace ts {
|
||||
Unreachable,
|
||||
Start,
|
||||
Label,
|
||||
LoopLabel,
|
||||
Assignment,
|
||||
Condition
|
||||
}
|
||||
|
||||
40
tests/baselines/reference/controlFlowIteration.js
Normal file
40
tests/baselines/reference/controlFlowIteration.js
Normal file
@@ -0,0 +1,40 @@
|
||||
//// [controlFlowIteration.ts]
|
||||
|
||||
let cond: boolean;
|
||||
|
||||
function ff() {
|
||||
let x: string | undefined;
|
||||
while (true) {
|
||||
if (cond) {
|
||||
x = "";
|
||||
}
|
||||
else {
|
||||
if (x) {
|
||||
x.length;
|
||||
}
|
||||
if (x) {
|
||||
x.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// [controlFlowIteration.js]
|
||||
var cond;
|
||||
function ff() {
|
||||
var x;
|
||||
while (true) {
|
||||
if (cond) {
|
||||
x = "";
|
||||
}
|
||||
else {
|
||||
if (x) {
|
||||
x.length;
|
||||
}
|
||||
if (x) {
|
||||
x.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
39
tests/baselines/reference/controlFlowIteration.symbols
Normal file
39
tests/baselines/reference/controlFlowIteration.symbols
Normal file
@@ -0,0 +1,39 @@
|
||||
=== tests/cases/conformance/controlFlow/controlFlowIteration.ts ===
|
||||
|
||||
let cond: boolean;
|
||||
>cond : Symbol(cond, Decl(controlFlowIteration.ts, 1, 3))
|
||||
|
||||
function ff() {
|
||||
>ff : Symbol(ff, Decl(controlFlowIteration.ts, 1, 18))
|
||||
|
||||
let x: string | undefined;
|
||||
>x : Symbol(x, Decl(controlFlowIteration.ts, 4, 7))
|
||||
|
||||
while (true) {
|
||||
if (cond) {
|
||||
>cond : Symbol(cond, Decl(controlFlowIteration.ts, 1, 3))
|
||||
|
||||
x = "";
|
||||
>x : Symbol(x, Decl(controlFlowIteration.ts, 4, 7))
|
||||
}
|
||||
else {
|
||||
if (x) {
|
||||
>x : Symbol(x, Decl(controlFlowIteration.ts, 4, 7))
|
||||
|
||||
x.length;
|
||||
>x.length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowIteration.ts, 4, 7))
|
||||
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
}
|
||||
if (x) {
|
||||
>x : Symbol(x, Decl(controlFlowIteration.ts, 4, 7))
|
||||
|
||||
x.length;
|
||||
>x.length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
>x : Symbol(x, Decl(controlFlowIteration.ts, 4, 7))
|
||||
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
43
tests/baselines/reference/controlFlowIteration.types
Normal file
43
tests/baselines/reference/controlFlowIteration.types
Normal file
@@ -0,0 +1,43 @@
|
||||
=== tests/cases/conformance/controlFlow/controlFlowIteration.ts ===
|
||||
|
||||
let cond: boolean;
|
||||
>cond : boolean
|
||||
|
||||
function ff() {
|
||||
>ff : () => void
|
||||
|
||||
let x: string | undefined;
|
||||
>x : string | undefined
|
||||
|
||||
while (true) {
|
||||
>true : boolean
|
||||
|
||||
if (cond) {
|
||||
>cond : boolean
|
||||
|
||||
x = "";
|
||||
>x = "" : string
|
||||
>x : string | undefined
|
||||
>"" : string
|
||||
}
|
||||
else {
|
||||
if (x) {
|
||||
>x : string | undefined
|
||||
|
||||
x.length;
|
||||
>x.length : number
|
||||
>x : string
|
||||
>length : number
|
||||
}
|
||||
if (x) {
|
||||
>x : string | undefined
|
||||
|
||||
x.length;
|
||||
>x.length : number
|
||||
>x : string
|
||||
>length : number
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
20
tests/cases/conformance/controlFlow/controlFlowIteration.ts
Normal file
20
tests/cases/conformance/controlFlow/controlFlowIteration.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
// @strictNullChecks: true
|
||||
|
||||
let cond: boolean;
|
||||
|
||||
function ff() {
|
||||
let x: string | undefined;
|
||||
while (true) {
|
||||
if (cond) {
|
||||
x = "";
|
||||
}
|
||||
else {
|
||||
if (x) {
|
||||
x.length;
|
||||
}
|
||||
if (x) {
|
||||
x.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user