Merge pull request #10815 from Microsoft/controlFlowOuterVariable
Fix outer variable control flow analysis
This commit is contained in:
commit
766eccaf97
5 changed files with 118 additions and 1 deletions
|
@ -8920,6 +8920,7 @@ namespace ts {
|
|||
const isParameter = getRootDeclaration(declaration).kind === SyntaxKind.Parameter;
|
||||
const declarationContainer = getControlFlowContainer(declaration);
|
||||
let flowContainer = getControlFlowContainer(node);
|
||||
const isOuterVariable = flowContainer !== declarationContainer;
|
||||
// When the control flow originates in a function expression or arrow function and we are referencing
|
||||
// a const variable or parameter from an outer function, we extend the origin of the control flow
|
||||
// analysis to include the immediately enclosing function.
|
||||
|
@ -8932,7 +8933,7 @@ namespace ts {
|
|||
// the entire control flow graph from the variable's declaration (i.e. when the flow container and
|
||||
// declaration container are the same).
|
||||
const assumeInitialized = !strictNullChecks || (type.flags & TypeFlags.Any) !== 0 || isParameter ||
|
||||
flowContainer !== declarationContainer || isInAmbientContext(declaration);
|
||||
isOuterVariable || isInAmbientContext(declaration);
|
||||
const flowType = getFlowTypeOfReference(node, type, assumeInitialized, flowContainer);
|
||||
// A variable is considered uninitialized when it is possible to analyze the entire control flow graph
|
||||
// from declaration to use, and when the variable's declared type doesn't include undefined but the
|
||||
|
|
26
tests/baselines/reference/controlFlowOuterVariable.js
Normal file
26
tests/baselines/reference/controlFlowOuterVariable.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
//// [controlFlowOuterVariable.ts]
|
||||
|
||||
// Repros from #10641
|
||||
|
||||
const CONFIG = {
|
||||
foo: '',
|
||||
setFoo: function(foo: string) {
|
||||
CONFIG.foo = foo;
|
||||
}
|
||||
};
|
||||
|
||||
const helper = function<T>(t: T[]) {
|
||||
helper(t.slice(1));
|
||||
}
|
||||
|
||||
//// [controlFlowOuterVariable.js]
|
||||
// Repros from #10641
|
||||
var CONFIG = {
|
||||
foo: '',
|
||||
setFoo: function (foo) {
|
||||
CONFIG.foo = foo;
|
||||
}
|
||||
};
|
||||
var helper = function (t) {
|
||||
helper(t.slice(1));
|
||||
};
|
34
tests/baselines/reference/controlFlowOuterVariable.symbols
Normal file
34
tests/baselines/reference/controlFlowOuterVariable.symbols
Normal file
|
@ -0,0 +1,34 @@
|
|||
=== tests/cases/compiler/controlFlowOuterVariable.ts ===
|
||||
|
||||
// Repros from #10641
|
||||
|
||||
const CONFIG = {
|
||||
>CONFIG : Symbol(CONFIG, Decl(controlFlowOuterVariable.ts, 3, 5))
|
||||
|
||||
foo: '',
|
||||
>foo : Symbol(foo, Decl(controlFlowOuterVariable.ts, 3, 16))
|
||||
|
||||
setFoo: function(foo: string) {
|
||||
>setFoo : Symbol(setFoo, Decl(controlFlowOuterVariable.ts, 4, 12))
|
||||
>foo : Symbol(foo, Decl(controlFlowOuterVariable.ts, 5, 21))
|
||||
|
||||
CONFIG.foo = foo;
|
||||
>CONFIG.foo : Symbol(foo, Decl(controlFlowOuterVariable.ts, 3, 16))
|
||||
>CONFIG : Symbol(CONFIG, Decl(controlFlowOuterVariable.ts, 3, 5))
|
||||
>foo : Symbol(foo, Decl(controlFlowOuterVariable.ts, 3, 16))
|
||||
>foo : Symbol(foo, Decl(controlFlowOuterVariable.ts, 5, 21))
|
||||
}
|
||||
};
|
||||
|
||||
const helper = function<T>(t: T[]) {
|
||||
>helper : Symbol(helper, Decl(controlFlowOuterVariable.ts, 10, 5))
|
||||
>T : Symbol(T, Decl(controlFlowOuterVariable.ts, 10, 24))
|
||||
>t : Symbol(t, Decl(controlFlowOuterVariable.ts, 10, 27))
|
||||
>T : Symbol(T, Decl(controlFlowOuterVariable.ts, 10, 24))
|
||||
|
||||
helper(t.slice(1));
|
||||
>helper : Symbol(helper, Decl(controlFlowOuterVariable.ts, 10, 5))
|
||||
>t.slice : Symbol(Array.slice, Decl(lib.d.ts, --, --))
|
||||
>t : Symbol(t, Decl(controlFlowOuterVariable.ts, 10, 27))
|
||||
>slice : Symbol(Array.slice, Decl(lib.d.ts, --, --))
|
||||
}
|
42
tests/baselines/reference/controlFlowOuterVariable.types
Normal file
42
tests/baselines/reference/controlFlowOuterVariable.types
Normal file
|
@ -0,0 +1,42 @@
|
|||
=== tests/cases/compiler/controlFlowOuterVariable.ts ===
|
||||
|
||||
// Repros from #10641
|
||||
|
||||
const CONFIG = {
|
||||
>CONFIG : { foo: string; setFoo: (foo: string) => void; }
|
||||
>{ foo: '', setFoo: function(foo: string) { CONFIG.foo = foo; }} : { foo: string; setFoo: (foo: string) => void; }
|
||||
|
||||
foo: '',
|
||||
>foo : string
|
||||
>'' : string
|
||||
|
||||
setFoo: function(foo: string) {
|
||||
>setFoo : (foo: string) => void
|
||||
>function(foo: string) { CONFIG.foo = foo; } : (foo: string) => void
|
||||
>foo : string
|
||||
|
||||
CONFIG.foo = foo;
|
||||
>CONFIG.foo = foo : string
|
||||
>CONFIG.foo : string
|
||||
>CONFIG : { foo: string; setFoo: (foo: string) => void; }
|
||||
>foo : string
|
||||
>foo : string
|
||||
}
|
||||
};
|
||||
|
||||
const helper = function<T>(t: T[]) {
|
||||
>helper : <T>(t: T[]) => void
|
||||
>function<T>(t: T[]) { helper(t.slice(1));} : <T>(t: T[]) => void
|
||||
>T : T
|
||||
>t : T[]
|
||||
>T : T
|
||||
|
||||
helper(t.slice(1));
|
||||
>helper(t.slice(1)) : void
|
||||
>helper : <T>(t: T[]) => void
|
||||
>t.slice(1) : T[]
|
||||
>t.slice : (start?: number | undefined, end?: number | undefined) => T[]
|
||||
>t : T[]
|
||||
>slice : (start?: number | undefined, end?: number | undefined) => T[]
|
||||
>1 : number
|
||||
}
|
14
tests/cases/compiler/controlFlowOuterVariable.ts
Normal file
14
tests/cases/compiler/controlFlowOuterVariable.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
// @strictNullChecks: true
|
||||
|
||||
// Repros from #10641
|
||||
|
||||
const CONFIG = {
|
||||
foo: '',
|
||||
setFoo: function(foo: string) {
|
||||
CONFIG.foo = foo;
|
||||
}
|
||||
};
|
||||
|
||||
const helper = function<T>(t: T[]) {
|
||||
helper(t.slice(1));
|
||||
}
|
Loading…
Reference in a new issue