mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
* fix CFA for BindingElement. #49759 * fix Parameter * fix controlFlowBindingPatternOrder * fix bindParameterFlow * add tests * refactor * refactor * refactor
This commit is contained in:
+35
-12
@@ -850,6 +850,9 @@ namespace ts {
|
||||
case SyntaxKind.BindingElement:
|
||||
bindBindingElementFlow(node as BindingElement);
|
||||
break;
|
||||
case SyntaxKind.Parameter:
|
||||
bindParameterFlow(node as ParameterDeclaration);
|
||||
break;
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
@@ -1655,20 +1658,40 @@ namespace ts {
|
||||
}
|
||||
|
||||
function bindBindingElementFlow(node: BindingElement) {
|
||||
if (isBindingPattern(node.name)) {
|
||||
// When evaluating a binding pattern, the initializer is evaluated before the binding pattern, per:
|
||||
// - https://tc39.es/ecma262/#sec-destructuring-binding-patterns-runtime-semantics-iteratorbindinginitialization
|
||||
// - `BindingElement: BindingPattern Initializer?`
|
||||
// - https://tc39.es/ecma262/#sec-runtime-semantics-keyedbindinginitialization
|
||||
// - `BindingElement: BindingPattern Initializer?`
|
||||
bind(node.dotDotDotToken);
|
||||
bind(node.propertyName);
|
||||
bind(node.initializer);
|
||||
bind(node.name);
|
||||
// When evaluating a binding pattern, the initializer is evaluated before the binding pattern, per:
|
||||
// - https://tc39.es/ecma262/#sec-destructuring-binding-patterns-runtime-semantics-iteratorbindinginitialization
|
||||
// - `BindingElement: BindingPattern Initializer?`
|
||||
// - https://tc39.es/ecma262/#sec-runtime-semantics-keyedbindinginitialization
|
||||
// - `BindingElement: BindingPattern Initializer?`
|
||||
bind(node.dotDotDotToken);
|
||||
bind(node.propertyName);
|
||||
bindInitializer(node.initializer);
|
||||
bind(node.name);
|
||||
}
|
||||
|
||||
function bindParameterFlow(node: ParameterDeclaration) {
|
||||
bindEach(node.modifiers);
|
||||
bind(node.dotDotDotToken);
|
||||
bind(node.questionToken);
|
||||
bind(node.type);
|
||||
bindInitializer(node.initializer);
|
||||
bind(node.name);
|
||||
}
|
||||
|
||||
// a BindingElement/Parameter does not have side effects if initializers are not evaluated and used. (see GH#49759)
|
||||
function bindInitializer(node: Expression | undefined) {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
bindEachChild(node);
|
||||
const entryFlow = currentFlow;
|
||||
bind(node);
|
||||
if (entryFlow === unreachableFlow || entryFlow === currentFlow) {
|
||||
return;
|
||||
}
|
||||
const exitFlow = createBranchLabel();
|
||||
addAntecedent(exitFlow, entryFlow);
|
||||
addAntecedent(exitFlow, currentFlow);
|
||||
currentFlow = finishFlowLabel(exitFlow);
|
||||
}
|
||||
|
||||
function bindJSDocTypeAlias(node: JSDocTypedefTag | JSDocCallbackTag | JSDocEnumTag) {
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
//// [controlFlowBindingElement.ts]
|
||||
{
|
||||
const data = { param: 'value' };
|
||||
|
||||
const {
|
||||
param = (() => { throw new Error('param is not defined') })(),
|
||||
} = data;
|
||||
|
||||
console.log(param); // should not trigger 'Unreachable code detected.'
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
const data = { param: 'value' };
|
||||
|
||||
let foo: string | undefined = "";
|
||||
const {
|
||||
param = (() => { throw new Error('param is not defined') })(),
|
||||
} = data;
|
||||
|
||||
foo; // should be string
|
||||
}
|
||||
|
||||
{
|
||||
const data = { param: 'value' };
|
||||
|
||||
let foo: string | undefined = "";
|
||||
const {
|
||||
param = (() => { foo = undefined })(),
|
||||
} = data;
|
||||
|
||||
foo; // should be string | undefined
|
||||
}
|
||||
|
||||
{
|
||||
const data = { param: 'value' };
|
||||
|
||||
let foo: string | undefined = "";
|
||||
const {
|
||||
param = (() => { return "" + 1 })(),
|
||||
} = data;
|
||||
|
||||
foo; // should be string
|
||||
}
|
||||
|
||||
{
|
||||
interface Window {
|
||||
window: Window;
|
||||
}
|
||||
|
||||
let foo: string | undefined;
|
||||
let window = {} as Window;
|
||||
window.window = window;
|
||||
|
||||
const { [(() => { foo = ""; return 'window' as const })()]:
|
||||
{ [(() => { return 'window' as const })()]: bar } } = window;
|
||||
|
||||
foo; // should be string
|
||||
}
|
||||
|
||||
{
|
||||
interface Window {
|
||||
window: Window;
|
||||
}
|
||||
|
||||
let foo: string | undefined;
|
||||
let window = {} as Window;
|
||||
window.window = window;
|
||||
|
||||
const { [(() => { return 'window' as const })()]:
|
||||
{ [(() => { foo = ""; return 'window' as const })()]: bar } } = window;
|
||||
|
||||
foo; // should be string
|
||||
}
|
||||
|
||||
{
|
||||
interface Window {
|
||||
window: Window;
|
||||
}
|
||||
|
||||
let foo: string | undefined;
|
||||
let window = {} as Window;
|
||||
window.window = window;
|
||||
|
||||
const { [(() => { return 'window' as const })()]:
|
||||
{ [(() => { return 'window' as const })()]: bar = (() => { foo = ""; return window; })() } } = window;
|
||||
|
||||
foo; // should be string | undefined
|
||||
}
|
||||
|
||||
|
||||
//// [controlFlowBindingElement.js]
|
||||
{
|
||||
var data = { param: 'value' };
|
||||
var _a = data.param, param = _a === void 0 ? (function () { throw new Error('param is not defined'); })() : _a;
|
||||
console.log(param); // should not trigger 'Unreachable code detected.'
|
||||
}
|
||||
{
|
||||
var data = { param: 'value' };
|
||||
var foo = "";
|
||||
var _b = data.param, param = _b === void 0 ? (function () { throw new Error('param is not defined'); })() : _b;
|
||||
foo; // should be string
|
||||
}
|
||||
{
|
||||
var data = { param: 'value' };
|
||||
var foo_1 = "";
|
||||
var _c = data.param, param = _c === void 0 ? (function () { foo_1 = undefined; })() : _c;
|
||||
foo_1; // should be string | undefined
|
||||
}
|
||||
{
|
||||
var data = { param: 'value' };
|
||||
var foo = "";
|
||||
var _d = data.param, param = _d === void 0 ? (function () { return "" + 1; })() : _d;
|
||||
foo; // should be string
|
||||
}
|
||||
{
|
||||
var foo_2;
|
||||
var window_1 = {};
|
||||
window_1.window = window_1;
|
||||
var _e = window_1, _f = (function () { foo_2 = ""; return 'window'; })(), _g = (function () { return 'window'; })(), bar = _e[_f][_g];
|
||||
foo_2; // should be string
|
||||
}
|
||||
{
|
||||
var foo_3;
|
||||
var window_2 = {};
|
||||
window_2.window = window_2;
|
||||
var _h = window_2, _j = (function () { return 'window'; })(), _k = (function () { foo_3 = ""; return 'window'; })(), bar = _h[_j][_k];
|
||||
foo_3; // should be string
|
||||
}
|
||||
{
|
||||
var foo_4;
|
||||
var window_3 = {};
|
||||
window_3.window = window_3;
|
||||
var _l = window_3, _m = (function () { return 'window'; })(), _o = (function () { return 'window'; })(), _p = _l[_m][_o], bar = _p === void 0 ? (function () { foo_4 = ""; return window_3; })() : _p;
|
||||
foo_4; // should be string | undefined
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
=== tests/cases/conformance/controlFlow/controlFlowBindingElement.ts ===
|
||||
{
|
||||
const data = { param: 'value' };
|
||||
>data : Symbol(data, Decl(controlFlowBindingElement.ts, 1, 9))
|
||||
>param : Symbol(param, Decl(controlFlowBindingElement.ts, 1, 19))
|
||||
|
||||
const {
|
||||
param = (() => { throw new Error('param is not defined') })(),
|
||||
>param : Symbol(param, Decl(controlFlowBindingElement.ts, 3, 11))
|
||||
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
} = data;
|
||||
>data : Symbol(data, Decl(controlFlowBindingElement.ts, 1, 9))
|
||||
|
||||
console.log(param); // should not trigger 'Unreachable code detected.'
|
||||
>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, --, --))
|
||||
>param : Symbol(param, Decl(controlFlowBindingElement.ts, 3, 11))
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
const data = { param: 'value' };
|
||||
>data : Symbol(data, Decl(controlFlowBindingElement.ts, 12, 9))
|
||||
>param : Symbol(param, Decl(controlFlowBindingElement.ts, 12, 19))
|
||||
|
||||
let foo: string | undefined = "";
|
||||
>foo : Symbol(foo, Decl(controlFlowBindingElement.ts, 14, 7))
|
||||
|
||||
const {
|
||||
param = (() => { throw new Error('param is not defined') })(),
|
||||
>param : Symbol(param, Decl(controlFlowBindingElement.ts, 15, 11))
|
||||
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
} = data;
|
||||
>data : Symbol(data, Decl(controlFlowBindingElement.ts, 12, 9))
|
||||
|
||||
foo; // should be string
|
||||
>foo : Symbol(foo, Decl(controlFlowBindingElement.ts, 14, 7))
|
||||
}
|
||||
|
||||
{
|
||||
const data = { param: 'value' };
|
||||
>data : Symbol(data, Decl(controlFlowBindingElement.ts, 23, 9))
|
||||
>param : Symbol(param, Decl(controlFlowBindingElement.ts, 23, 19))
|
||||
|
||||
let foo: string | undefined = "";
|
||||
>foo : Symbol(foo, Decl(controlFlowBindingElement.ts, 25, 7))
|
||||
|
||||
const {
|
||||
param = (() => { foo = undefined })(),
|
||||
>param : Symbol(param, Decl(controlFlowBindingElement.ts, 26, 11))
|
||||
>foo : Symbol(foo, Decl(controlFlowBindingElement.ts, 25, 7))
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
} = data;
|
||||
>data : Symbol(data, Decl(controlFlowBindingElement.ts, 23, 9))
|
||||
|
||||
foo; // should be string | undefined
|
||||
>foo : Symbol(foo, Decl(controlFlowBindingElement.ts, 25, 7))
|
||||
}
|
||||
|
||||
{
|
||||
const data = { param: 'value' };
|
||||
>data : Symbol(data, Decl(controlFlowBindingElement.ts, 34, 9))
|
||||
>param : Symbol(param, Decl(controlFlowBindingElement.ts, 34, 19))
|
||||
|
||||
let foo: string | undefined = "";
|
||||
>foo : Symbol(foo, Decl(controlFlowBindingElement.ts, 36, 7))
|
||||
|
||||
const {
|
||||
param = (() => { return "" + 1 })(),
|
||||
>param : Symbol(param, Decl(controlFlowBindingElement.ts, 37, 11))
|
||||
|
||||
} = data;
|
||||
>data : Symbol(data, Decl(controlFlowBindingElement.ts, 34, 9))
|
||||
|
||||
foo; // should be string
|
||||
>foo : Symbol(foo, Decl(controlFlowBindingElement.ts, 36, 7))
|
||||
}
|
||||
|
||||
{
|
||||
interface Window {
|
||||
>Window : Symbol(Window, Decl(controlFlowBindingElement.ts, 44, 1))
|
||||
|
||||
window: Window;
|
||||
>window : Symbol(Window.window, Decl(controlFlowBindingElement.ts, 45, 22))
|
||||
>Window : Symbol(Window, Decl(controlFlowBindingElement.ts, 44, 1))
|
||||
}
|
||||
|
||||
let foo: string | undefined;
|
||||
>foo : Symbol(foo, Decl(controlFlowBindingElement.ts, 49, 7))
|
||||
|
||||
let window = {} as Window;
|
||||
>window : Symbol(window, Decl(controlFlowBindingElement.ts, 50, 7))
|
||||
>Window : Symbol(Window, Decl(controlFlowBindingElement.ts, 44, 1))
|
||||
|
||||
window.window = window;
|
||||
>window.window : Symbol(Window.window, Decl(controlFlowBindingElement.ts, 45, 22))
|
||||
>window : Symbol(window, Decl(controlFlowBindingElement.ts, 50, 7))
|
||||
>window : Symbol(Window.window, Decl(controlFlowBindingElement.ts, 45, 22))
|
||||
>window : Symbol(window, Decl(controlFlowBindingElement.ts, 50, 7))
|
||||
|
||||
const { [(() => { foo = ""; return 'window' as const })()]:
|
||||
>foo : Symbol(foo, Decl(controlFlowBindingElement.ts, 49, 7))
|
||||
>const : Symbol(const)
|
||||
|
||||
{ [(() => { return 'window' as const })()]: bar } } = window;
|
||||
>const : Symbol(const)
|
||||
>bar : Symbol(bar, Decl(controlFlowBindingElement.ts, 54, 9))
|
||||
>window : Symbol(window, Decl(controlFlowBindingElement.ts, 50, 7))
|
||||
|
||||
foo; // should be string
|
||||
>foo : Symbol(foo, Decl(controlFlowBindingElement.ts, 49, 7))
|
||||
}
|
||||
|
||||
{
|
||||
interface Window {
|
||||
>Window : Symbol(Window, Decl(controlFlowBindingElement.ts, 59, 1))
|
||||
|
||||
window: Window;
|
||||
>window : Symbol(Window.window, Decl(controlFlowBindingElement.ts, 60, 22))
|
||||
>Window : Symbol(Window, Decl(controlFlowBindingElement.ts, 59, 1))
|
||||
}
|
||||
|
||||
let foo: string | undefined;
|
||||
>foo : Symbol(foo, Decl(controlFlowBindingElement.ts, 64, 7))
|
||||
|
||||
let window = {} as Window;
|
||||
>window : Symbol(window, Decl(controlFlowBindingElement.ts, 65, 7))
|
||||
>Window : Symbol(Window, Decl(controlFlowBindingElement.ts, 59, 1))
|
||||
|
||||
window.window = window;
|
||||
>window.window : Symbol(Window.window, Decl(controlFlowBindingElement.ts, 60, 22))
|
||||
>window : Symbol(window, Decl(controlFlowBindingElement.ts, 65, 7))
|
||||
>window : Symbol(Window.window, Decl(controlFlowBindingElement.ts, 60, 22))
|
||||
>window : Symbol(window, Decl(controlFlowBindingElement.ts, 65, 7))
|
||||
|
||||
const { [(() => { return 'window' as const })()]:
|
||||
>const : Symbol(const)
|
||||
|
||||
{ [(() => { foo = ""; return 'window' as const })()]: bar } } = window;
|
||||
>foo : Symbol(foo, Decl(controlFlowBindingElement.ts, 64, 7))
|
||||
>const : Symbol(const)
|
||||
>bar : Symbol(bar, Decl(controlFlowBindingElement.ts, 69, 9))
|
||||
>window : Symbol(window, Decl(controlFlowBindingElement.ts, 65, 7))
|
||||
|
||||
foo; // should be string
|
||||
>foo : Symbol(foo, Decl(controlFlowBindingElement.ts, 64, 7))
|
||||
}
|
||||
|
||||
{
|
||||
interface Window {
|
||||
>Window : Symbol(Window, Decl(controlFlowBindingElement.ts, 74, 1))
|
||||
|
||||
window: Window;
|
||||
>window : Symbol(Window.window, Decl(controlFlowBindingElement.ts, 75, 22))
|
||||
>Window : Symbol(Window, Decl(controlFlowBindingElement.ts, 74, 1))
|
||||
}
|
||||
|
||||
let foo: string | undefined;
|
||||
>foo : Symbol(foo, Decl(controlFlowBindingElement.ts, 79, 7))
|
||||
|
||||
let window = {} as Window;
|
||||
>window : Symbol(window, Decl(controlFlowBindingElement.ts, 80, 7))
|
||||
>Window : Symbol(Window, Decl(controlFlowBindingElement.ts, 74, 1))
|
||||
|
||||
window.window = window;
|
||||
>window.window : Symbol(Window.window, Decl(controlFlowBindingElement.ts, 75, 22))
|
||||
>window : Symbol(window, Decl(controlFlowBindingElement.ts, 80, 7))
|
||||
>window : Symbol(Window.window, Decl(controlFlowBindingElement.ts, 75, 22))
|
||||
>window : Symbol(window, Decl(controlFlowBindingElement.ts, 80, 7))
|
||||
|
||||
const { [(() => { return 'window' as const })()]:
|
||||
>const : Symbol(const)
|
||||
|
||||
{ [(() => { return 'window' as const })()]: bar = (() => { foo = ""; return window; })() } } = window;
|
||||
>const : Symbol(const)
|
||||
>bar : Symbol(bar, Decl(controlFlowBindingElement.ts, 84, 9))
|
||||
>foo : Symbol(foo, Decl(controlFlowBindingElement.ts, 79, 7))
|
||||
>window : Symbol(window, Decl(controlFlowBindingElement.ts, 80, 7))
|
||||
>window : Symbol(window, Decl(controlFlowBindingElement.ts, 80, 7))
|
||||
|
||||
foo; // should be string | undefined
|
||||
>foo : Symbol(foo, Decl(controlFlowBindingElement.ts, 79, 7))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
=== tests/cases/conformance/controlFlow/controlFlowBindingElement.ts ===
|
||||
{
|
||||
const data = { param: 'value' };
|
||||
>data : { param: string; }
|
||||
>{ param: 'value' } : { param: string; }
|
||||
>param : string
|
||||
>'value' : "value"
|
||||
|
||||
const {
|
||||
param = (() => { throw new Error('param is not defined') })(),
|
||||
>param : string
|
||||
>(() => { throw new Error('param is not defined') })() : never
|
||||
>(() => { throw new Error('param is not defined') }) : () => never
|
||||
>() => { throw new Error('param is not defined') } : () => never
|
||||
>new Error('param is not defined') : Error
|
||||
>Error : ErrorConstructor
|
||||
>'param is not defined' : "param is not defined"
|
||||
|
||||
} = data;
|
||||
>data : { param: string; }
|
||||
|
||||
console.log(param); // should not trigger 'Unreachable code detected.'
|
||||
>console.log(param) : void
|
||||
>console.log : (...data: any[]) => void
|
||||
>console : Console
|
||||
>log : (...data: any[]) => void
|
||||
>param : string
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
const data = { param: 'value' };
|
||||
>data : { param: string; }
|
||||
>{ param: 'value' } : { param: string; }
|
||||
>param : string
|
||||
>'value' : "value"
|
||||
|
||||
let foo: string | undefined = "";
|
||||
>foo : string | undefined
|
||||
>"" : ""
|
||||
|
||||
const {
|
||||
param = (() => { throw new Error('param is not defined') })(),
|
||||
>param : string
|
||||
>(() => { throw new Error('param is not defined') })() : never
|
||||
>(() => { throw new Error('param is not defined') }) : () => never
|
||||
>() => { throw new Error('param is not defined') } : () => never
|
||||
>new Error('param is not defined') : Error
|
||||
>Error : ErrorConstructor
|
||||
>'param is not defined' : "param is not defined"
|
||||
|
||||
} = data;
|
||||
>data : { param: string; }
|
||||
|
||||
foo; // should be string
|
||||
>foo : string
|
||||
}
|
||||
|
||||
{
|
||||
const data = { param: 'value' };
|
||||
>data : { param: string; }
|
||||
>{ param: 'value' } : { param: string; }
|
||||
>param : string
|
||||
>'value' : "value"
|
||||
|
||||
let foo: string | undefined = "";
|
||||
>foo : string | undefined
|
||||
>"" : ""
|
||||
|
||||
const {
|
||||
param = (() => { foo = undefined })(),
|
||||
>param : string | void
|
||||
>(() => { foo = undefined })() : void
|
||||
>(() => { foo = undefined }) : () => void
|
||||
>() => { foo = undefined } : () => void
|
||||
>foo = undefined : undefined
|
||||
>foo : string | undefined
|
||||
>undefined : undefined
|
||||
|
||||
} = data;
|
||||
>data : { param: string; }
|
||||
|
||||
foo; // should be string | undefined
|
||||
>foo : string | undefined
|
||||
}
|
||||
|
||||
{
|
||||
const data = { param: 'value' };
|
||||
>data : { param: string; }
|
||||
>{ param: 'value' } : { param: string; }
|
||||
>param : string
|
||||
>'value' : "value"
|
||||
|
||||
let foo: string | undefined = "";
|
||||
>foo : string | undefined
|
||||
>"" : ""
|
||||
|
||||
const {
|
||||
param = (() => { return "" + 1 })(),
|
||||
>param : string
|
||||
>(() => { return "" + 1 })() : string
|
||||
>(() => { return "" + 1 }) : () => string
|
||||
>() => { return "" + 1 } : () => string
|
||||
>"" + 1 : string
|
||||
>"" : ""
|
||||
>1 : 1
|
||||
|
||||
} = data;
|
||||
>data : { param: string; }
|
||||
|
||||
foo; // should be string
|
||||
>foo : string
|
||||
}
|
||||
|
||||
{
|
||||
interface Window {
|
||||
window: Window;
|
||||
>window : Window
|
||||
}
|
||||
|
||||
let foo: string | undefined;
|
||||
>foo : string | undefined
|
||||
|
||||
let window = {} as Window;
|
||||
>window : Window
|
||||
>{} as Window : Window
|
||||
>{} : {}
|
||||
|
||||
window.window = window;
|
||||
>window.window = window : Window
|
||||
>window.window : Window
|
||||
>window : Window
|
||||
>window : Window
|
||||
>window : Window
|
||||
|
||||
const { [(() => { foo = ""; return 'window' as const })()]:
|
||||
>(() => { foo = ""; return 'window' as const })() : "window"
|
||||
>(() => { foo = ""; return 'window' as const }) : () => "window"
|
||||
>() => { foo = ""; return 'window' as const } : () => "window"
|
||||
>foo = "" : ""
|
||||
>foo : string | undefined
|
||||
>"" : ""
|
||||
>'window' as const : "window"
|
||||
>'window' : "window"
|
||||
|
||||
{ [(() => { return 'window' as const })()]: bar } } = window;
|
||||
>(() => { return 'window' as const })() : "window"
|
||||
>(() => { return 'window' as const }) : () => "window"
|
||||
>() => { return 'window' as const } : () => "window"
|
||||
>'window' as const : "window"
|
||||
>'window' : "window"
|
||||
>bar : Window
|
||||
>window : Window
|
||||
|
||||
foo; // should be string
|
||||
>foo : string
|
||||
}
|
||||
|
||||
{
|
||||
interface Window {
|
||||
window: Window;
|
||||
>window : Window
|
||||
}
|
||||
|
||||
let foo: string | undefined;
|
||||
>foo : string | undefined
|
||||
|
||||
let window = {} as Window;
|
||||
>window : Window
|
||||
>{} as Window : Window
|
||||
>{} : {}
|
||||
|
||||
window.window = window;
|
||||
>window.window = window : Window
|
||||
>window.window : Window
|
||||
>window : Window
|
||||
>window : Window
|
||||
>window : Window
|
||||
|
||||
const { [(() => { return 'window' as const })()]:
|
||||
>(() => { return 'window' as const })() : "window"
|
||||
>(() => { return 'window' as const }) : () => "window"
|
||||
>() => { return 'window' as const } : () => "window"
|
||||
>'window' as const : "window"
|
||||
>'window' : "window"
|
||||
|
||||
{ [(() => { foo = ""; return 'window' as const })()]: bar } } = window;
|
||||
>(() => { foo = ""; return 'window' as const })() : "window"
|
||||
>(() => { foo = ""; return 'window' as const }) : () => "window"
|
||||
>() => { foo = ""; return 'window' as const } : () => "window"
|
||||
>foo = "" : ""
|
||||
>foo : string | undefined
|
||||
>"" : ""
|
||||
>'window' as const : "window"
|
||||
>'window' : "window"
|
||||
>bar : Window
|
||||
>window : Window
|
||||
|
||||
foo; // should be string
|
||||
>foo : string
|
||||
}
|
||||
|
||||
{
|
||||
interface Window {
|
||||
window: Window;
|
||||
>window : Window
|
||||
}
|
||||
|
||||
let foo: string | undefined;
|
||||
>foo : string | undefined
|
||||
|
||||
let window = {} as Window;
|
||||
>window : Window
|
||||
>{} as Window : Window
|
||||
>{} : {}
|
||||
|
||||
window.window = window;
|
||||
>window.window = window : Window
|
||||
>window.window : Window
|
||||
>window : Window
|
||||
>window : Window
|
||||
>window : Window
|
||||
|
||||
const { [(() => { return 'window' as const })()]:
|
||||
>(() => { return 'window' as const })() : "window"
|
||||
>(() => { return 'window' as const }) : () => "window"
|
||||
>() => { return 'window' as const } : () => "window"
|
||||
>'window' as const : "window"
|
||||
>'window' : "window"
|
||||
|
||||
{ [(() => { return 'window' as const })()]: bar = (() => { foo = ""; return window; })() } } = window;
|
||||
>(() => { return 'window' as const })() : "window"
|
||||
>(() => { return 'window' as const }) : () => "window"
|
||||
>() => { return 'window' as const } : () => "window"
|
||||
>'window' as const : "window"
|
||||
>'window' : "window"
|
||||
>bar : Window
|
||||
>(() => { foo = ""; return window; })() : Window
|
||||
>(() => { foo = ""; return window; }) : () => Window
|
||||
>() => { foo = ""; return window; } : () => Window
|
||||
>foo = "" : ""
|
||||
>foo : string | undefined
|
||||
>"" : ""
|
||||
>window : Window
|
||||
>window : Window
|
||||
|
||||
foo; // should be string | undefined
|
||||
>foo : string | undefined
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
tests/cases/conformance/controlFlow/controlFlowBindingPatternOrder.ts(10,11): error TS2322: Type '0 | 9' is not assignable to type '9'.
|
||||
Type '0' is not assignable to type '9'.
|
||||
tests/cases/conformance/controlFlow/controlFlowBindingPatternOrder.ts(25,11): error TS2322: Type '0 | 9 | 8' is not assignable to type '0 | 8'.
|
||||
Type '9' is not assignable to type '0 | 8'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/controlFlow/controlFlowBindingPatternOrder.ts (2 errors) ====
|
||||
// https://github.com/microsoft/TypeScript/pull/41094#issuecomment-716044363
|
||||
{
|
||||
let a: 0 | 1 = 0;
|
||||
const [{ [(a = 1)]: b } = [9, a] as const] = [];
|
||||
const bb: 0 = b;
|
||||
}
|
||||
{
|
||||
let a: 0 | 1 = 1;
|
||||
const [{ [a]: b } = [9, a = 0] as const] = [];
|
||||
const bb: 9 = b;
|
||||
~~
|
||||
!!! error TS2322: Type '0 | 9' is not assignable to type '9'.
|
||||
!!! error TS2322: Type '0' is not assignable to type '9'.
|
||||
}
|
||||
{
|
||||
let a: 0 | 1 | 2 = 1;
|
||||
const [{ [a]: b } = [9, a = 0, 5] as const] = [];
|
||||
const bb: 0 | 9 = b;
|
||||
}
|
||||
{
|
||||
let a: 0 | 1 = 0;
|
||||
const [{ [(a = 1)]: b } = [9, a] as const] = [[9, 8] as const];
|
||||
const bb: 0 | 8 = b;
|
||||
}
|
||||
{
|
||||
let a: 0 | 1 = 1;
|
||||
const [{ [a]: b } = [a = 0, 9] as const] = [[8, 9] as const];
|
||||
const bb: 0 | 8 = b;
|
||||
~~
|
||||
!!! error TS2322: Type '0 | 9 | 8' is not assignable to type '0 | 8'.
|
||||
!!! error TS2322: Type '9' is not assignable to type '0 | 8'.
|
||||
}
|
||||
@@ -29,25 +29,24 @@
|
||||
>b : Symbol(b, Decl(controlFlowBindingPatternOrder.ts, 8, 12))
|
||||
}
|
||||
{
|
||||
let a: 0 | 1 = 0;
|
||||
let a: 0 | 1 | 2 = 1;
|
||||
>a : Symbol(a, Decl(controlFlowBindingPatternOrder.ts, 12, 7))
|
||||
|
||||
const [{ [(a = 1)]: b } = [9, a] as const] = [[9, 8] as const];
|
||||
const [{ [a]: b } = [9, a = 0, 5] as const] = [];
|
||||
>a : Symbol(a, Decl(controlFlowBindingPatternOrder.ts, 12, 7))
|
||||
>b : Symbol(b, Decl(controlFlowBindingPatternOrder.ts, 13, 12))
|
||||
>a : Symbol(a, Decl(controlFlowBindingPatternOrder.ts, 12, 7))
|
||||
>const : Symbol(const)
|
||||
>const : Symbol(const)
|
||||
|
||||
const bb: 0 | 8 = b;
|
||||
const bb: 0 | 9 = b;
|
||||
>bb : Symbol(bb, Decl(controlFlowBindingPatternOrder.ts, 14, 9))
|
||||
>b : Symbol(b, Decl(controlFlowBindingPatternOrder.ts, 13, 12))
|
||||
}
|
||||
{
|
||||
let a: 0 | 1 = 1;
|
||||
let a: 0 | 1 = 0;
|
||||
>a : Symbol(a, Decl(controlFlowBindingPatternOrder.ts, 17, 7))
|
||||
|
||||
const [{ [a]: b } = [a = 0, 9] as const] = [[8, 9] as const];
|
||||
const [{ [(a = 1)]: b } = [9, a] as const] = [[9, 8] as const];
|
||||
>a : Symbol(a, Decl(controlFlowBindingPatternOrder.ts, 17, 7))
|
||||
>b : Symbol(b, Decl(controlFlowBindingPatternOrder.ts, 18, 12))
|
||||
>a : Symbol(a, Decl(controlFlowBindingPatternOrder.ts, 17, 7))
|
||||
@@ -58,3 +57,18 @@
|
||||
>bb : Symbol(bb, Decl(controlFlowBindingPatternOrder.ts, 19, 9))
|
||||
>b : Symbol(b, Decl(controlFlowBindingPatternOrder.ts, 18, 12))
|
||||
}
|
||||
{
|
||||
let a: 0 | 1 = 1;
|
||||
>a : Symbol(a, Decl(controlFlowBindingPatternOrder.ts, 22, 7))
|
||||
|
||||
const [{ [a]: b } = [a = 0, 9] as const] = [[8, 9] as const];
|
||||
>a : Symbol(a, Decl(controlFlowBindingPatternOrder.ts, 22, 7))
|
||||
>b : Symbol(b, Decl(controlFlowBindingPatternOrder.ts, 23, 12))
|
||||
>a : Symbol(a, Decl(controlFlowBindingPatternOrder.ts, 22, 7))
|
||||
>const : Symbol(const)
|
||||
>const : Symbol(const)
|
||||
|
||||
const bb: 0 | 8 = b;
|
||||
>bb : Symbol(bb, Decl(controlFlowBindingPatternOrder.ts, 24, 9))
|
||||
>b : Symbol(b, Decl(controlFlowBindingPatternOrder.ts, 23, 12))
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
>1 : 1
|
||||
|
||||
const [{ [a]: b } = [9, a = 0] as const] = [];
|
||||
>a : 0
|
||||
>b : 9
|
||||
>a : 0 | 1
|
||||
>b : 0 | 9
|
||||
>[9, a = 0] as const : readonly [9, 0]
|
||||
>[9, a = 0] : readonly [9, 0]
|
||||
>9 : 9
|
||||
@@ -39,7 +39,28 @@
|
||||
|
||||
const bb: 9 = b;
|
||||
>bb : 9
|
||||
>b : 9
|
||||
>b : 0 | 9
|
||||
}
|
||||
{
|
||||
let a: 0 | 1 | 2 = 1;
|
||||
>a : 0 | 1 | 2
|
||||
>1 : 1
|
||||
|
||||
const [{ [a]: b } = [9, a = 0, 5] as const] = [];
|
||||
>a : 0 | 1
|
||||
>b : 0 | 9
|
||||
>[9, a = 0, 5] as const : readonly [9, 0, 5]
|
||||
>[9, a = 0, 5] : readonly [9, 0, 5]
|
||||
>9 : 9
|
||||
>a = 0 : 0
|
||||
>a : 0 | 1 | 2
|
||||
>0 : 0
|
||||
>5 : 5
|
||||
>[] : []
|
||||
|
||||
const bb: 0 | 9 = b;
|
||||
>bb : 0 | 9
|
||||
>b : 0 | 9
|
||||
}
|
||||
{
|
||||
let a: 0 | 1 = 0;
|
||||
@@ -72,8 +93,8 @@
|
||||
>1 : 1
|
||||
|
||||
const [{ [a]: b } = [a = 0, 9] as const] = [[8, 9] as const];
|
||||
>a : 0
|
||||
>b : 0 | 8
|
||||
>a : 0 | 1
|
||||
>b : 0 | 9 | 8
|
||||
>[a = 0, 9] as const : readonly [0, 9]
|
||||
>[a = 0, 9] : readonly [0, 9]
|
||||
>a = 0 : 0
|
||||
@@ -88,5 +109,5 @@
|
||||
|
||||
const bb: 0 | 8 = b;
|
||||
>bb : 0 | 8
|
||||
>b : 0 | 8
|
||||
>b : 0 | 9 | 8
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
//// [controlFlowParameter.ts]
|
||||
function f1(
|
||||
required: unknown = (() => {
|
||||
throw new Error("bad");
|
||||
})()
|
||||
) {
|
||||
console.log("ok"); // should not trigger 'Unreachable code detected.'
|
||||
}
|
||||
|
||||
function f2(
|
||||
a: number | string | undefined,
|
||||
required: unknown = (() => {
|
||||
a = 1;
|
||||
})()
|
||||
) {
|
||||
a; // should be number | string | undefined
|
||||
}
|
||||
|
||||
function f3(
|
||||
a: number | string | undefined = 1,
|
||||
required: unknown = (() => {
|
||||
a = "";
|
||||
})()
|
||||
) {
|
||||
a; // should be number | string
|
||||
}
|
||||
|
||||
function f4(
|
||||
a: number | string | undefined = 1,
|
||||
{ [(a = "")]: b } = {} as any
|
||||
) {
|
||||
a; // should be string
|
||||
}
|
||||
|
||||
|
||||
//// [controlFlowParameter.js]
|
||||
function f1(required) {
|
||||
if (required === void 0) { required = (function () {
|
||||
throw new Error("bad");
|
||||
})(); }
|
||||
console.log("ok"); // should not trigger 'Unreachable code detected.'
|
||||
}
|
||||
function f2(a, required) {
|
||||
if (required === void 0) { required = (function () {
|
||||
a = 1;
|
||||
})(); }
|
||||
a; // should be number | string | undefined
|
||||
}
|
||||
function f3(a, required) {
|
||||
if (a === void 0) { a = 1; }
|
||||
if (required === void 0) { required = (function () {
|
||||
a = "";
|
||||
})(); }
|
||||
a; // should be number | string
|
||||
}
|
||||
function f4(a, _a) {
|
||||
if (a === void 0) { a = 1; }
|
||||
var _b = _a === void 0 ? {} : _a, _c = (a = ""), b = _b[_c];
|
||||
a; // should be string
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
=== tests/cases/conformance/controlFlow/controlFlowParameter.ts ===
|
||||
function f1(
|
||||
>f1 : Symbol(f1, Decl(controlFlowParameter.ts, 0, 0))
|
||||
|
||||
required: unknown = (() => {
|
||||
>required : Symbol(required, Decl(controlFlowParameter.ts, 0, 12))
|
||||
|
||||
throw new Error("bad");
|
||||
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
})()
|
||||
) {
|
||||
console.log("ok"); // should not trigger 'Unreachable code detected.'
|
||||
>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, --, --))
|
||||
}
|
||||
|
||||
function f2(
|
||||
>f2 : Symbol(f2, Decl(controlFlowParameter.ts, 6, 1))
|
||||
|
||||
a: number | string | undefined,
|
||||
>a : Symbol(a, Decl(controlFlowParameter.ts, 8, 12))
|
||||
|
||||
required: unknown = (() => {
|
||||
>required : Symbol(required, Decl(controlFlowParameter.ts, 9, 33))
|
||||
|
||||
a = 1;
|
||||
>a : Symbol(a, Decl(controlFlowParameter.ts, 8, 12))
|
||||
|
||||
})()
|
||||
) {
|
||||
a; // should be number | string | undefined
|
||||
>a : Symbol(a, Decl(controlFlowParameter.ts, 8, 12))
|
||||
}
|
||||
|
||||
function f3(
|
||||
>f3 : Symbol(f3, Decl(controlFlowParameter.ts, 15, 1))
|
||||
|
||||
a: number | string | undefined = 1,
|
||||
>a : Symbol(a, Decl(controlFlowParameter.ts, 17, 12))
|
||||
|
||||
required: unknown = (() => {
|
||||
>required : Symbol(required, Decl(controlFlowParameter.ts, 18, 37))
|
||||
|
||||
a = "";
|
||||
>a : Symbol(a, Decl(controlFlowParameter.ts, 17, 12))
|
||||
|
||||
})()
|
||||
) {
|
||||
a; // should be number | string
|
||||
>a : Symbol(a, Decl(controlFlowParameter.ts, 17, 12))
|
||||
}
|
||||
|
||||
function f4(
|
||||
>f4 : Symbol(f4, Decl(controlFlowParameter.ts, 24, 1))
|
||||
|
||||
a: number | string | undefined = 1,
|
||||
>a : Symbol(a, Decl(controlFlowParameter.ts, 26, 12))
|
||||
|
||||
{ [(a = "")]: b } = {} as any
|
||||
>a : Symbol(a, Decl(controlFlowParameter.ts, 26, 12))
|
||||
>b : Symbol(b, Decl(controlFlowParameter.ts, 28, 3))
|
||||
|
||||
) {
|
||||
a; // should be string
|
||||
>a : Symbol(a, Decl(controlFlowParameter.ts, 26, 12))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
=== tests/cases/conformance/controlFlow/controlFlowParameter.ts ===
|
||||
function f1(
|
||||
>f1 : (required?: unknown) => void
|
||||
|
||||
required: unknown = (() => {
|
||||
>required : unknown
|
||||
>(() => { throw new Error("bad"); })() : never
|
||||
>(() => { throw new Error("bad"); }) : () => never
|
||||
>() => { throw new Error("bad"); } : () => never
|
||||
|
||||
throw new Error("bad");
|
||||
>new Error("bad") : Error
|
||||
>Error : ErrorConstructor
|
||||
>"bad" : "bad"
|
||||
|
||||
})()
|
||||
) {
|
||||
console.log("ok"); // should not trigger 'Unreachable code detected.'
|
||||
>console.log("ok") : void
|
||||
>console.log : (...data: any[]) => void
|
||||
>console : Console
|
||||
>log : (...data: any[]) => void
|
||||
>"ok" : "ok"
|
||||
}
|
||||
|
||||
function f2(
|
||||
>f2 : (a: number | string | undefined, required?: unknown) => void
|
||||
|
||||
a: number | string | undefined,
|
||||
>a : string | number | undefined
|
||||
|
||||
required: unknown = (() => {
|
||||
>required : unknown
|
||||
>(() => { a = 1; })() : void
|
||||
>(() => { a = 1; }) : () => void
|
||||
>() => { a = 1; } : () => void
|
||||
|
||||
a = 1;
|
||||
>a = 1 : 1
|
||||
>a : string | number | undefined
|
||||
>1 : 1
|
||||
|
||||
})()
|
||||
) {
|
||||
a; // should be number | string | undefined
|
||||
>a : string | number | undefined
|
||||
}
|
||||
|
||||
function f3(
|
||||
>f3 : (a?: number | string | undefined, required?: unknown) => void
|
||||
|
||||
a: number | string | undefined = 1,
|
||||
>a : string | number | undefined
|
||||
>1 : 1
|
||||
|
||||
required: unknown = (() => {
|
||||
>required : unknown
|
||||
>(() => { a = ""; })() : void
|
||||
>(() => { a = ""; }) : () => void
|
||||
>() => { a = ""; } : () => void
|
||||
|
||||
a = "";
|
||||
>a = "" : ""
|
||||
>a : string | number | undefined
|
||||
>"" : ""
|
||||
|
||||
})()
|
||||
) {
|
||||
a; // should be number | string
|
||||
>a : string | number
|
||||
}
|
||||
|
||||
function f4(
|
||||
>f4 : (a?: number | string | undefined, { [(a = "")]: b }?: any) => void
|
||||
|
||||
a: number | string | undefined = 1,
|
||||
>a : string | number | undefined
|
||||
>1 : 1
|
||||
|
||||
{ [(a = "")]: b } = {} as any
|
||||
>(a = "") : ""
|
||||
>a = "" : ""
|
||||
>a : string | number | undefined
|
||||
>"" : ""
|
||||
>b : any
|
||||
>{} as any : any
|
||||
>{} : {}
|
||||
|
||||
) {
|
||||
a; // should be string
|
||||
>a : string
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
// @strictNullChecks: true
|
||||
// @allowUnreachableCode: false
|
||||
{
|
||||
const data = { param: 'value' };
|
||||
|
||||
const {
|
||||
param = (() => { throw new Error('param is not defined') })(),
|
||||
} = data;
|
||||
|
||||
console.log(param); // should not trigger 'Unreachable code detected.'
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
const data = { param: 'value' };
|
||||
|
||||
let foo: string | undefined = "";
|
||||
const {
|
||||
param = (() => { throw new Error('param is not defined') })(),
|
||||
} = data;
|
||||
|
||||
foo; // should be string
|
||||
}
|
||||
|
||||
{
|
||||
const data = { param: 'value' };
|
||||
|
||||
let foo: string | undefined = "";
|
||||
const {
|
||||
param = (() => { foo = undefined })(),
|
||||
} = data;
|
||||
|
||||
foo; // should be string | undefined
|
||||
}
|
||||
|
||||
{
|
||||
const data = { param: 'value' };
|
||||
|
||||
let foo: string | undefined = "";
|
||||
const {
|
||||
param = (() => { return "" + 1 })(),
|
||||
} = data;
|
||||
|
||||
foo; // should be string
|
||||
}
|
||||
|
||||
{
|
||||
interface Window {
|
||||
window: Window;
|
||||
}
|
||||
|
||||
let foo: string | undefined;
|
||||
let window = {} as Window;
|
||||
window.window = window;
|
||||
|
||||
const { [(() => { foo = ""; return 'window' as const })()]:
|
||||
{ [(() => { return 'window' as const })()]: bar } } = window;
|
||||
|
||||
foo; // should be string
|
||||
}
|
||||
|
||||
{
|
||||
interface Window {
|
||||
window: Window;
|
||||
}
|
||||
|
||||
let foo: string | undefined;
|
||||
let window = {} as Window;
|
||||
window.window = window;
|
||||
|
||||
const { [(() => { return 'window' as const })()]:
|
||||
{ [(() => { foo = ""; return 'window' as const })()]: bar } } = window;
|
||||
|
||||
foo; // should be string
|
||||
}
|
||||
|
||||
{
|
||||
interface Window {
|
||||
window: Window;
|
||||
}
|
||||
|
||||
let foo: string | undefined;
|
||||
let window = {} as Window;
|
||||
window.window = window;
|
||||
|
||||
const { [(() => { return 'window' as const })()]:
|
||||
{ [(() => { return 'window' as const })()]: bar = (() => { foo = ""; return window; })() } } = window;
|
||||
|
||||
foo; // should be string | undefined
|
||||
}
|
||||
@@ -12,6 +12,11 @@
|
||||
const [{ [a]: b } = [9, a = 0] as const] = [];
|
||||
const bb: 9 = b;
|
||||
}
|
||||
{
|
||||
let a: 0 | 1 | 2 = 1;
|
||||
const [{ [a]: b } = [9, a = 0, 5] as const] = [];
|
||||
const bb: 0 | 9 = b;
|
||||
}
|
||||
{
|
||||
let a: 0 | 1 = 0;
|
||||
const [{ [(a = 1)]: b } = [9, a] as const] = [[9, 8] as const];
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// @strictNullChecks: true
|
||||
// @allowUnreachableCode: false
|
||||
function f1(
|
||||
required: unknown = (() => {
|
||||
throw new Error("bad");
|
||||
})()
|
||||
) {
|
||||
console.log("ok"); // should not trigger 'Unreachable code detected.'
|
||||
}
|
||||
|
||||
function f2(
|
||||
a: number | string | undefined,
|
||||
required: unknown = (() => {
|
||||
a = 1;
|
||||
})()
|
||||
) {
|
||||
a; // should be number | string | undefined
|
||||
}
|
||||
|
||||
function f3(
|
||||
a: number | string | undefined = 1,
|
||||
required: unknown = (() => {
|
||||
a = "";
|
||||
})()
|
||||
) {
|
||||
a; // should be number | string
|
||||
}
|
||||
|
||||
function f4(
|
||||
a: number | string | undefined = 1,
|
||||
{ [(a = "")]: b } = {} as any
|
||||
) {
|
||||
a; // should be string
|
||||
}
|
||||
Reference in New Issue
Block a user