Skip to content

Improve binding element type inference - #50241

Closed
Babak K. Shandiz (babakks) wants to merge 5 commits into
microsoft:mainfrom
babakks:improve-binding-element-type-inference
Closed

Improve binding element type inference#50241
Babak K. Shandiz (babakks) wants to merge 5 commits into
microsoft:mainfrom
babakks:improve-binding-element-type-inference

Conversation

@babakks

@babakksBabak K. Shandiz (babakks) commented Aug 9, 2022

Copy link
Copy Markdown
Contributor

Fixes#49989

Problem

There were two problems:

  1. Type inference for variables declared by binding elements was not accurate. For example, for the declaration below the type of both variables were inferred to be any (instead of number).

    const[a,b=a]=[1];
  2. With noImplicitAny option enabled, a false circular relationship error would be emitted:

    'a' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.(7022)
    

Cause

The problems were hidden in the getTypeFromBindingElement function whose responsibility is to infer the type of variables defined as binding elements without looking onto the declaration initializer (the array literal, [1], in the example above).

When a binding element itself had a default value (as in b = a) and that default value involved any sibling variable (i.e., variables defined in the same binding pattern, here a) then the inquiry for the type of the default value would begin and eventually result in a circular relationship error down the path. This error made the type checker to infer the types as any.

Solution

Since the getTypeFromBindingElement function just needs to narrowly look inside the binding elements/patterns, we can skip further type checkings (that is falling back to any) when any other sibling variables are somehow involved in the default value expressions.

Although this seems to be an ad-hoc/one-off kind of solution, type checkings for binding elements are deeply integrated with other parts of the type checker, and solving the problem in a more generic way, I believe, requires greater knowledge of the code base (compared to mine, of course).

Effect on the existing behavior

Three existing test cases were affected by this PR, fortunately in a good way. They're now correctly inferring the type number. Also, the circular relationship error was erased from one similar test case.

New test case

A new test case, destructuringArrayBindingPatternAndAssignment5.ts, was added that contains cases where default values somehow reference other sibling variables.

… sibling definitions
Signed-off-by: Babak K. Shandiz <babak.k.shandiz@gmail.com>
diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index abf3e9d..793ffb3 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -9445,8 +9445,33 @@ namespace ts {
// The type implied by a binding pattern is independent of context, so we check the initializer with no
// contextual type or, if the element itself is a binding pattern, with the type implied by that binding
// pattern.
- const contextualType = isBindingPattern(element.name) ? getTypeFromBindingPattern(element.name, /*includePatternInType*/ true, /*reportErrors*/ false) : unknownType;
- return addOptionality(widenTypeInferredFromInitializer(element, checkDeclarationInitializer(element, CheckMode.Normal, contextualType)));
+ if (isBindingPattern(element.name)) {
+ const contextualType = getTypeFromBindingPattern(element.name, /*includePatternInType*/ true, /*reportErrors*/ false);
+ return addOptionality(widenTypeInferredFromInitializer(element, checkDeclarationInitializer(element, CheckMode.Normal, contextualType)));
+ }
+
+ // (microsoft#49989)
+ // In cases where the intitializer is an identifier referencing a sibling symbol (i.e., one that is
+ // defined in the same declaration) a false circular relationship will be concluded. For example, take
+ // the declarations below:
+ //
+ // const [a, b = a] = [1];
+ // const {a, b = a} = {a: 1};
+ //
+ // Here, when the `element` is the second binding element (i.e., `b = a`) the initializer is `a` which
+ // itself is defined within the same binding pattern.
+ //
+ // So, we check the initializer expression for any references to sibling symbols and if any, then we'd
+ // conclude the binding element type as `unknownType` and thus skip further circulations in type
+ // checking.
+ const siblings = mapDefined(element.parent.elements, x => x !== element && isBindingElement(x) && isIdentifier(x.name) ? x : undefined);
+ const checkIsSiblingInvolved = (node: Node) => {
+ const declaration = isIdentifier(node) && getReferencedValueDeclaration(node);
+ return declaration && isBindingElement(declaration) && siblings.includes(declaration);
+ };
+ const isSiblingElementInvolded = checkIsSiblingInvolved(element.initializer) || forEachChildRecursively(element.initializer, checkIsSiblingInvolved);
+ return isSiblingElementInvolded ? anyType
+ : addOptionality(widenTypeInferredFromInitializer(element, checkDeclarationInitializer(element, CheckMode.Normal, unknownType)));
}
if (isBindingPattern(element.name)) {
return getTypeFromBindingPattern(element.name, includePatternInType, reportErrors);
Signed-off-by: Babak K. Shandiz <babak.k.shandiz@gmail.com>
diff --git a/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment5.js b/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment5.js
new file mode 100644
index 0000000000..003e92b
--- /dev/null
+++ b/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment5.js
@@ -0,0 +1,69 @@
+//// [destructuringArrayBindingPatternAndAssignment5.ts]
+// To be inferred as `number`
+function f1() {
+ const [a1, b1 = a1] = [1];
+ const [a2, b2 = 1 + a2] = [1];
+ const [a3, b3 = (() => 1 + a3)()] = [1];
+ const [a4, b4 = (() => (() => 1 + a4)() + 1)()] = [1];
+
+ function fn1([a1, b1 = a1] = [1]) { };
+ function fn2([a2, b2 = 1 + a2] = [1]) { };
+ function fn3([a3, b3 = (() => 1 + a3)()] = [1]) { };
+ function fn4([a4, b4 = (() => (() => 1 + a4)() + 1)()] = [1]) { };
+}
+
+// To be inferred as `string`
+function f2() {
+ const [a1, b1 = a1] = ['hi'];
+ const [a2, b2 = [a2, '!'].join()] = ['hi'];
+ const [a3, b3 = (() => [a3, '!'].join())()] = ['hi'];
+ const [a4, b4 = (() => (() => [a4, '!'].join())() + '!')()] = ['hi'];
+}
+
+// To be inferred as `string | number`
+function f3() {
+ const [a1, b1 = a1] = ['hi', 1];
+ const [a2, b2 = [a2, '!'].join()] = ['hi', 1];
+ const [a3, b3 = (() => [a3, '!'].join())()] = ['hi', 1];
+ const [a4, b4 = (() => (() => [a4, '!'].join())() + '!')()] = ['hi', 1];
+}
+
+
+//// [destructuringArrayBindingPatternAndAssignment5.js]
+// To be inferred as `number`
+function f1() {
+ var _a = [1], a1 = _a[0], _b = _a[1], b1 = _b === void 0 ? a1 : _b;
+ var _c = [1], a2 = _c[0], _d = _c[1], b2 = _d === void 0 ? 1 + a2 : _d;
+ var _e = [1], a3 = _e[0], _f = _e[1], b3 = _f === void 0 ? (function () { return 1 + a3; })() : _f;
+ var _g = [1], a4 = _g[0], _h = _g[1], b4 = _h === void 0 ? (function () { return (function () { return 1 + a4; })() + 1; })() : _h;
+ function fn1(_a) {
+ var _b = _a === void 0 ? [1] : _a, a1 = _b[0], _c = _b[1], b1 = _c === void 0 ? a1 : _c;
+ }
+ ;
+ function fn2(_a) {
+ var _b = _a === void 0 ? [1] : _a, a2 = _b[0], _c = _b[1], b2 = _c === void 0 ? 1 + a2 : _c;
+ }
+ ;
+ function fn3(_a) {
+ var _b = _a === void 0 ? [1] : _a, a3 = _b[0], _c = _b[1], b3 = _c === void 0 ? (function () { return 1 + a3; })() : _c;
+ }
+ ;
+ function fn4(_a) {
+ var _b = _a === void 0 ? [1] : _a, a4 = _b[0], _c = _b[1], b4 = _c === void 0 ? (function () { return (function () { return 1 + a4; })() + 1; })() : _c;
+ }
+ ;
+}
+// To be inferred as `string`
+function f2() {
+ var _a = ['hi'], a1 = _a[0], _b = _a[1], b1 = _b === void 0 ? a1 : _b;
+ var _c = ['hi'], a2 = _c[0], _d = _c[1], b2 = _d === void 0 ? [a2, '!'].join() : _d;
+ var _e = ['hi'], a3 = _e[0], _f = _e[1], b3 = _f === void 0 ? (function () { return [a3, '!'].join(); })() : _f;
+ var _g = ['hi'], a4 = _g[0], _h = _g[1], b4 = _h === void 0 ? (function () { return (function () { return [a4, '!'].join(); })() + '!'; })() : _h;
+}
+// To be inferred as `string | number`
+function f3() {
+ var _a = ['hi', 1], a1 = _a[0], _b = _a[1], b1 = _b === void 0 ? a1 : _b;
+ var _c = ['hi', 1], a2 = _c[0], _d = _c[1], b2 = _d === void 0 ? [a2, '!'].join() : _d;
+ var _e = ['hi', 1], a3 = _e[0], _f = _e[1], b3 = _f === void 0 ? (function () { return [a3, '!'].join(); })() : _f;
+ var _g = ['hi', 1], a4 = _g[0], _h = _g[1], b4 = _h === void 0 ? (function () { return (function () { return [a4, '!'].join(); })() + '!'; })() : _h;
+}
diff --git a/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment5.symbols b/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment5.symbols
new file mode 100644
index 0000000000..298e9d5
--- /dev/null
+++ b/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment5.symbols
@@ -0,0 +1,112 @@
+=== tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAssignment5.ts ===
+// To be inferred as `number`
+function f1() {
+>f1 : Symbol(f1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 0, 0))
+
+ const [a1, b1 = a1] = [1];
+>a1 : Symbol(a1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 2, 11))
+>b1 : Symbol(b1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 2, 14))
+>a1 : Symbol(a1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 2, 11))
+
+ const [a2, b2 = 1 + a2] = [1];
+>a2 : Symbol(a2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 3, 11))
+>b2 : Symbol(b2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 3, 14))
+>a2 : Symbol(a2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 3, 11))
+
+ const [a3, b3 = (() => 1 + a3)()] = [1];
+>a3 : Symbol(a3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 4, 11))
+>b3 : Symbol(b3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 4, 14))
+>a3 : Symbol(a3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 4, 11))
+
+ const [a4, b4 = (() => (() => 1 + a4)() + 1)()] = [1];
+>a4 : Symbol(a4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 5, 11))
+>b4 : Symbol(b4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 5, 14))
+>a4 : Symbol(a4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 5, 11))
+
+ function fn1([a1, b1 = a1] = [1]) { };
+>fn1 : Symbol(fn1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 5, 58))
+>a1 : Symbol(a1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 7, 18))
+>b1 : Symbol(b1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 7, 21))
+>a1 : Symbol(a1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 7, 18))
+
+ function fn2([a2, b2 = 1 + a2] = [1]) { };
+>fn2 : Symbol(fn2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 7, 42))
+>a2 : Symbol(a2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 8, 18))
+>b2 : Symbol(b2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 8, 21))
+>a2 : Symbol(a2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 8, 18))
+
+ function fn3([a3, b3 = (() => 1 + a3)()] = [1]) { };
+>fn3 : Symbol(fn3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 8, 46))
+>a3 : Symbol(a3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 9, 18))
+>b3 : Symbol(b3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 9, 21))
+>a3 : Symbol(a3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 9, 18))
+
+ function fn4([a4, b4 = (() => (() => 1 + a4)() + 1)()] = [1]) { };
+>fn4 : Symbol(fn4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 9, 56))
+>a4 : Symbol(a4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 10, 18))
+>b4 : Symbol(b4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 10, 21))
+>a4 : Symbol(a4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 10, 18))
+}
+
+// To be inferred as `string`
+function f2() {
+>f2 : Symbol(f2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 11, 1))
+
+ const [a1, b1 = a1] = ['hi'];
+>a1 : Symbol(a1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 15, 11))
+>b1 : Symbol(b1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 15, 14))
+>a1 : Symbol(a1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 15, 11))
+
+ const [a2, b2 = [a2, '!'].join()] = ['hi'];
+>a2 : Symbol(a2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 16, 11))
+>b2 : Symbol(b2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 16, 14))
+>[a2, '!'].join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
+>a2 : Symbol(a2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 16, 11))
+>join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
+
+ const [a3, b3 = (() => [a3, '!'].join())()] = ['hi'];
+>a3 : Symbol(a3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 17, 11))
+>b3 : Symbol(b3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 17, 14))
+>[a3, '!'].join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
+>a3 : Symbol(a3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 17, 11))
+>join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
+
+ const [a4, b4 = (() => (() => [a4, '!'].join())() + '!')()] = ['hi'];
+>a4 : Symbol(a4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 18, 11))
+>b4 : Symbol(b4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 18, 14))
+>[a4, '!'].join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
+>a4 : Symbol(a4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 18, 11))
+>join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
+}
+
+// To be inferred as `string | number`
+function f3() {
+>f3 : Symbol(f3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 19, 1))
+
+ const [a1, b1 = a1] = ['hi', 1];
+>a1 : Symbol(a1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 23, 11))
+>b1 : Symbol(b1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 23, 14))
+>a1 : Symbol(a1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 23, 11))
+
+ const [a2, b2 = [a2, '!'].join()] = ['hi', 1];
+>a2 : Symbol(a2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 24, 11))
+>b2 : Symbol(b2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 24, 14))
+>[a2, '!'].join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
+>a2 : Symbol(a2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 24, 11))
+>join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
+
+ const [a3, b3 = (() => [a3, '!'].join())()] = ['hi', 1];
+>a3 : Symbol(a3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 25, 11))
+>b3 : Symbol(b3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 25, 14))
+>[a3, '!'].join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
+>a3 : Symbol(a3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 25, 11))
+>join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
+
+ const [a4, b4 = (() => (() => [a4, '!'].join())() + '!')()] = ['hi', 1];
+>a4 : Symbol(a4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 26, 11))
+>b4 : Symbol(b4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 26, 14))
+>[a4, '!'].join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
+>a4 : Symbol(a4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 26, 11))
+>join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
+}
+
diff --git a/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment5.types b/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment5.types
new file mode 100644
index 0000000000..34bad2f
--- /dev/null
+++ b/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment5.types
@@ -0,0 +1,222 @@
+=== tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAssignment5.ts ===
+// To be inferred as `number`
+function f1() {
+>f1 : () => void
+
+ const [a1, b1 = a1] = [1];
+>a1 : number
+>b1 : number
+>a1 : number
+>[1] : [number]
+>1 : 1
+
+ const [a2, b2 = 1 + a2] = [1];
+>a2 : number
+>b2 : number
+>1 + a2 : number
+>1 : 1
+>a2 : number
+>[1] : [number]
+>1 : 1
+
+ const [a3, b3 = (() => 1 + a3)()] = [1];
+>a3 : number
+>b3 : number
+>(() => 1 + a3)() : number
+>(() => 1 + a3) : () => number
+>() => 1 + a3 : () => number
+>1 + a3 : number
+>1 : 1
+>a3 : number
+>[1] : [number]
+>1 : 1
+
+ const [a4, b4 = (() => (() => 1 + a4)() + 1)()] = [1];
+>a4 : number
+>b4 : number
+>(() => (() => 1 + a4)() + 1)() : number
+>(() => (() => 1 + a4)() + 1) : () => number
+>() => (() => 1 + a4)() + 1 : () => number
+>(() => 1 + a4)() + 1 : number
+>(() => 1 + a4)() : number
+>(() => 1 + a4) : () => number
+>() => 1 + a4 : () => number
+>1 + a4 : number
+>1 : 1
+>a4 : number
+>1 : 1
+>[1] : [number]
+>1 : 1
+
+ function fn1([a1, b1 = a1] = [1]) { };
+>fn1 : ([a1, b1]?: [number, any?]) => void
+>a1 : number
+>b1 : any
+>a1 : number
+>[1] : [number]
+>1 : 1
+
+ function fn2([a2, b2 = 1 + a2] = [1]) { };
+>fn2 : ([a2, b2]?: [number, any?]) => void
+>a2 : number
+>b2 : any
+>1 + a2 : number
+>1 : 1
+>a2 : number
+>[1] : [number]
+>1 : 1
+
+ function fn3([a3, b3 = (() => 1 + a3)()] = [1]) { };
+>fn3 : ([a3, b3]?: [number, any?]) => void
+>a3 : number
+>b3 : any
+>(() => 1 + a3)() : number
+>(() => 1 + a3) : () => number
+>() => 1 + a3 : () => number
+>1 + a3 : number
+>1 : 1
+>a3 : number
+>[1] : [number]
+>1 : 1
+
+ function fn4([a4, b4 = (() => (() => 1 + a4)() + 1)()] = [1]) { };
+>fn4 : ([a4, b4]?: [number, any?]) => void
+>a4 : number
+>b4 : any
+>(() => (() => 1 + a4)() + 1)() : number
+>(() => (() => 1 + a4)() + 1) : () => number
+>() => (() => 1 + a4)() + 1 : () => number
+>(() => 1 + a4)() + 1 : number
+>(() => 1 + a4)() : number
+>(() => 1 + a4) : () => number
+>() => 1 + a4 : () => number
+>1 + a4 : number
+>1 : 1
+>a4 : number
+>1 : 1
+>[1] : [number]
+>1 : 1
+}
+
+// To be inferred as `string`
+function f2() {
+>f2 : () => void
+
+ const [a1, b1 = a1] = ['hi'];
+>a1 : string
+>b1 : string
+>a1 : string
+>['hi'] : [string]
+>'hi' : "hi"
+
+ const [a2, b2 = [a2, '!'].join()] = ['hi'];
+>a2 : string
+>b2 : string
+>[a2, '!'].join() : string
+>[a2, '!'].join : (separator?: string) => string
+>[a2, '!'] : string[]
+>a2 : string
+>'!' : "!"
+>join : (separator?: string) => string
+>['hi'] : [string]
+>'hi' : "hi"
+
+ const [a3, b3 = (() => [a3, '!'].join())()] = ['hi'];
+>a3 : string
+>b3 : string
+>(() => [a3, '!'].join())() : string
+>(() => [a3, '!'].join()) : () => string
+>() => [a3, '!'].join() : () => string
+>[a3, '!'].join() : string
+>[a3, '!'].join : (separator?: string) => string
+>[a3, '!'] : string[]
+>a3 : string
+>'!' : "!"
+>join : (separator?: string) => string
+>['hi'] : [string]
+>'hi' : "hi"
+
+ const [a4, b4 = (() => (() => [a4, '!'].join())() + '!')()] = ['hi'];
+>a4 : string
+>b4 : string
+>(() => (() => [a4, '!'].join())() + '!')() : string
+>(() => (() => [a4, '!'].join())() + '!') : () => string
+>() => (() => [a4, '!'].join())() + '!' : () => string
+>(() => [a4, '!'].join())() + '!' : string
+>(() => [a4, '!'].join())() : string
+>(() => [a4, '!'].join()) : () => string
+>() => [a4, '!'].join() : () => string
+>[a4, '!'].join() : string
+>[a4, '!'].join : (separator?: string) => string
+>[a4, '!'] : string[]
+>a4 : string
+>'!' : "!"
+>join : (separator?: string) => string
+>'!' : "!"
+>['hi'] : [string]
+>'hi' : "hi"
+}
+
+// To be inferred as `string | number`
+function f3() {
+>f3 : () => void
+
+ const [a1, b1 = a1] = ['hi', 1];
+>a1 : string
+>b1 : string | number
+>a1 : string
+>['hi', 1] : [string, number]
+>'hi' : "hi"
+>1 : 1
+
+ const [a2, b2 = [a2, '!'].join()] = ['hi', 1];
+>a2 : string
+>b2 : string | number
+>[a2, '!'].join() : string
+>[a2, '!'].join : (separator?: string) => string
+>[a2, '!'] : string[]
+>a2 : string
+>'!' : "!"
+>join : (separator?: string) => string
+>['hi', 1] : [string, number]
+>'hi' : "hi"
+>1 : 1
+
+ const [a3, b3 = (() => [a3, '!'].join())()] = ['hi', 1];
+>a3 : string
+>b3 : string | number
+>(() => [a3, '!'].join())() : string
+>(() => [a3, '!'].join()) : () => string
+>() => [a3, '!'].join() : () => string
+>[a3, '!'].join() : string
+>[a3, '!'].join : (separator?: string) => string
+>[a3, '!'] : string[]
+>a3 : string
+>'!' : "!"
+>join : (separator?: string) => string
+>['hi', 1] : [string, number]
+>'hi' : "hi"
+>1 : 1
+
+ const [a4, b4 = (() => (() => [a4, '!'].join())() + '!')()] = ['hi', 1];
+>a4 : string
+>b4 : string | number
+>(() => (() => [a4, '!'].join())() + '!')() : string
+>(() => (() => [a4, '!'].join())() + '!') : () => string
+>() => (() => [a4, '!'].join())() + '!' : () => string
+>(() => [a4, '!'].join())() + '!' : string
+>(() => [a4, '!'].join())() : string
+>(() => [a4, '!'].join()) : () => string
+>() => [a4, '!'].join() : () => string
+>[a4, '!'].join() : string
+>[a4, '!'].join : (separator?: string) => string
+>[a4, '!'] : string[]
+>a4 : string
+>'!' : "!"
+>join : (separator?: string) => string
+>'!' : "!"
+>['hi', 1] : [string, number]
+>'hi' : "hi"
+>1 : 1
+}
+
diff --git a/tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAssignment5.ts b/tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAssignment5.ts
new file mode 100644
index 0000000000..b14b985
--- /dev/null
+++ b/tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAssignment5.ts
@@ -0,0 +1,23 @@
+// To be inferred as `number`
+function f1() {
+ const [a1, b1 = a1] = [1];
+ const [a2, b2 = 1 + a2] = [1];
+ const [a3, b3 = (() => 1 + a3)()] = [1];
+ const [a4, b4 = (() => (() => 1 + a4)() + 1)()] = [1];
+}
+
+// To be inferred as `string`
+function f2() {
+ const [a1, b1 = a1] = ['hi'];
+ const [a2, b2 = [a2, '!'].join()] = ['hi'];
+ const [a3, b3 = (() => [a3, '!'].join())()] = ['hi'];
+ const [a4, b4 = (() => (() => [a4, '!'].join())() + '!')()] = ['hi'];
+}
+
+// To be inferred as `string | number`
+function f3() {
+ const [a1, b1 = a1] = ['hi', 1];
+ const [a2, b2 = [a2, '!'].join()] = ['hi', 1];
+ const [a3, b3 = (() => [a3, '!'].join())()] = ['hi', 1];
+ const [a4, b4 = (() => (() => [a4, '!'].join())() + '!')()] = ['hi', 1];
+}
Signed-off-by: Babak K. Shandiz <babak.k.shandiz@gmail.com>
diff --git a/tests/baselines/reference/dependentDestructuredVariables.errors.txt b/tests/baselines/reference/dependentDestructuredVariables.errors.txt
index e3704b5..7de0253 100644
--- a/tests/baselines/reference/dependentDestructuredVariables.errors.txt
+++ b/tests/baselines/reference/dependentDestructuredVariables.errors.txt
@@ -1,8 +1,7 @@
-tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(314,5): error TS7022: 'value1' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(314,5): error TS7031: Binding element 'value1' implicitly has an 'any' type.
-==== tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts (2 errors) ====
+==== tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts (1 errors) ====
type Action =
| { kind: 'A', payload: number }
| { kind: 'B', payload: string };
@@ -318,8 +317,6 @@ tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(314,5): er
function foo({
value1,
~~~~~~
-!!! error TS7022: 'value1' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
- ~~~~~~
!!! error TS7031: Binding element 'value1' implicitly has an 'any' type.
test1 = value1.test1,
test2 = value1.test2,
diff --git a/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment3.types b/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment3.types
index 5a0e03d..a1e95ea 100644
--- a/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment3.types
+++ b/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment3.types
@@ -1,28 +1,28 @@
=== tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAssignment3.ts ===
const [a, b = a] = [1]; // ok
->a : any
->b : any
->a : any
+>a : number
+>b : number
+>a : number
>[1] : [number]
>1 : 1
const [c, d = c, e = e] = [1]; // error for e = e
->c : any
->d : any
->c : any
+>c : number
+>d : number
+>c : number
>e : any
>e : any
>[1] : [number]
>1 : 1
const [f, g = f, h = i, i = f] = [1]; // error for h = i
->f : any
->g : any
->f : any
->h : any
->i : any
->i : any
->f : any
+>f : number
+>g : number
+>f : number
+>h : number
+>i : number
+>i : number
+>f : number
>[1] : [number]
>1 : 1
diff --git a/tests/baselines/reference/useBeforeDeclaration_destructuring.types b/tests/baselines/reference/useBeforeDeclaration_destructuring.types
index 935d320..d1ce6d7 100644
--- a/tests/baselines/reference/useBeforeDeclaration_destructuring.types
+++ b/tests/baselines/reference/useBeforeDeclaration_destructuring.types
@@ -1,11 +1,11 @@
=== tests/cases/compiler/useBeforeDeclaration_destructuring.ts ===
a;
->a : any
+>a : string
let {a, b = a} = {a: '', b: 1};
->a : any
->b : any
->a : any
+>a : string
+>b : string | number
+>a : string
>{a: '', b: 1} : { a: string; b?: number; }
>a : string
>'' : ""
@@ -13,7 +13,7 @@ let {a, b = a} = {a: '', b: 1};
>1 : 1
b;
->b : any
+>b : string | number
function test({c, d = c}: Record<string, number>) {}
>test : ({ c, d }: Record<string, number>) => void
@typescript-botTypeScript Bot (typescript-bot) added the For Backlog Bug PRs that fix a backlog bug label Aug 9, 2022
Signed-off-by: Babak K. Shandiz <babak.k.shandiz@gmail.com>
diff --git a/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment5.js b/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment5.js
index 003e92b..70ba454 100644
--- a/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment5.js
+++ b/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment5.js
@@ -5,11 +5,6 @@ function f1() {
const [a2, b2 = 1 + a2] = [1];
const [a3, b3 = (() => 1 + a3)()] = [1];
const [a4, b4 = (() => (() => 1 + a4)() + 1)()] = [1];
-
- function fn1([a1, b1 = a1] = [1]) { };
- function fn2([a2, b2 = 1 + a2] = [1]) { };
- function fn3([a3, b3 = (() => 1 + a3)()] = [1]) { };
- function fn4([a4, b4 = (() => (() => 1 + a4)() + 1)()] = [1]) { };
}
// To be inferred as `string`
@@ -36,22 +31,6 @@ function f1() {
var _c = [1], a2 = _c[0], _d = _c[1], b2 = _d === void 0 ? 1 + a2 : _d;
var _e = [1], a3 = _e[0], _f = _e[1], b3 = _f === void 0 ? (function () { return 1 + a3; })() : _f;
var _g = [1], a4 = _g[0], _h = _g[1], b4 = _h === void 0 ? (function () { return (function () { return 1 + a4; })() + 1; })() : _h;
- function fn1(_a) {
- var _b = _a === void 0 ? [1] : _a, a1 = _b[0], _c = _b[1], b1 = _c === void 0 ? a1 : _c;
- }
- ;
- function fn2(_a) {
- var _b = _a === void 0 ? [1] : _a, a2 = _b[0], _c = _b[1], b2 = _c === void 0 ? 1 + a2 : _c;
- }
- ;
- function fn3(_a) {
- var _b = _a === void 0 ? [1] : _a, a3 = _b[0], _c = _b[1], b3 = _c === void 0 ? (function () { return 1 + a3; })() : _c;
- }
- ;
- function fn4(_a) {
- var _b = _a === void 0 ? [1] : _a, a4 = _b[0], _c = _b[1], b4 = _c === void 0 ? (function () { return (function () { return 1 + a4; })() + 1; })() : _c;
- }
- ;
}
// To be inferred as `string`
function f2() {
diff --git a/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment5.symbols b/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment5.symbols
index 298e9d5..1bdbecf 100644
--- a/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment5.symbols
+++ b/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment5.symbols
@@ -22,91 +22,67 @@ function f1() {
>a4 : Symbol(a4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 5, 11))
>b4 : Symbol(b4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 5, 14))
>a4 : Symbol(a4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 5, 11))
-
- function fn1([a1, b1 = a1] = [1]) { };
->fn1 : Symbol(fn1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 5, 58))
->a1 : Symbol(a1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 7, 18))
->b1 : Symbol(b1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 7, 21))
->a1 : Symbol(a1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 7, 18))
-
- function fn2([a2, b2 = 1 + a2] = [1]) { };
->fn2 : Symbol(fn2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 7, 42))
->a2 : Symbol(a2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 8, 18))
->b2 : Symbol(b2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 8, 21))
->a2 : Symbol(a2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 8, 18))
-
- function fn3([a3, b3 = (() => 1 + a3)()] = [1]) { };
->fn3 : Symbol(fn3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 8, 46))
->a3 : Symbol(a3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 9, 18))
->b3 : Symbol(b3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 9, 21))
->a3 : Symbol(a3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 9, 18))
-
- function fn4([a4, b4 = (() => (() => 1 + a4)() + 1)()] = [1]) { };
->fn4 : Symbol(fn4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 9, 56))
->a4 : Symbol(a4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 10, 18))
->b4 : Symbol(b4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 10, 21))
->a4 : Symbol(a4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 10, 18))
}
// To be inferred as `string`
function f2() {
->f2 : Symbol(f2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 11, 1))
+>f2 : Symbol(f2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 6, 1))
const [a1, b1 = a1] = ['hi'];
->a1 : Symbol(a1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 15, 11))
->b1 : Symbol(b1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 15, 14))
->a1 : Symbol(a1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 15, 11))
+>a1 : Symbol(a1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 10, 11))
+>b1 : Symbol(b1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 10, 14))
+>a1 : Symbol(a1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 10, 11))
const [a2, b2 = [a2, '!'].join()] = ['hi'];
->a2 : Symbol(a2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 16, 11))
->b2 : Symbol(b2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 16, 14))
+>a2 : Symbol(a2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 11, 11))
+>b2 : Symbol(b2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 11, 14))
>[a2, '!'].join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
->a2 : Symbol(a2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 16, 11))
+>a2 : Symbol(a2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 11, 11))
>join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
const [a3, b3 = (() => [a3, '!'].join())()] = ['hi'];
->a3 : Symbol(a3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 17, 11))
->b3 : Symbol(b3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 17, 14))
+>a3 : Symbol(a3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 12, 11))
+>b3 : Symbol(b3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 12, 14))
>[a3, '!'].join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
->a3 : Symbol(a3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 17, 11))
+>a3 : Symbol(a3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 12, 11))
>join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
const [a4, b4 = (() => (() => [a4, '!'].join())() + '!')()] = ['hi'];
->a4 : Symbol(a4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 18, 11))
->b4 : Symbol(b4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 18, 14))
+>a4 : Symbol(a4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 13, 11))
+>b4 : Symbol(b4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 13, 14))
>[a4, '!'].join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
->a4 : Symbol(a4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 18, 11))
+>a4 : Symbol(a4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 13, 11))
>join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
}
// To be inferred as `string | number`
function f3() {
->f3 : Symbol(f3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 19, 1))
+>f3 : Symbol(f3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 14, 1))
const [a1, b1 = a1] = ['hi', 1];
->a1 : Symbol(a1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 23, 11))
->b1 : Symbol(b1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 23, 14))
->a1 : Symbol(a1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 23, 11))
+>a1 : Symbol(a1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 18, 11))
+>b1 : Symbol(b1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 18, 14))
+>a1 : Symbol(a1, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 18, 11))
const [a2, b2 = [a2, '!'].join()] = ['hi', 1];
->a2 : Symbol(a2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 24, 11))
->b2 : Symbol(b2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 24, 14))
+>a2 : Symbol(a2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 19, 11))
+>b2 : Symbol(b2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 19, 14))
>[a2, '!'].join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
->a2 : Symbol(a2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 24, 11))
+>a2 : Symbol(a2, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 19, 11))
>join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
const [a3, b3 = (() => [a3, '!'].join())()] = ['hi', 1];
->a3 : Symbol(a3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 25, 11))
->b3 : Symbol(b3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 25, 14))
+>a3 : Symbol(a3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 20, 11))
+>b3 : Symbol(b3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 20, 14))
>[a3, '!'].join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
->a3 : Symbol(a3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 25, 11))
+>a3 : Symbol(a3, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 20, 11))
>join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
const [a4, b4 = (() => (() => [a4, '!'].join())() + '!')()] = ['hi', 1];
->a4 : Symbol(a4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 26, 11))
->b4 : Symbol(b4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 26, 14))
+>a4 : Symbol(a4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 21, 11))
+>b4 : Symbol(b4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 21, 14))
>[a4, '!'].join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
->a4 : Symbol(a4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 26, 11))
+>a4 : Symbol(a4, Decl(destructuringArrayBindingPatternAndAssignment5.ts, 21, 11))
>join : Symbol(Array.join, Decl(lib.es5.d.ts, --, --))
}
diff --git a/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment5.types b/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment5.types
index 34bad2f..dd7092e 100644
--- a/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment5.types
+++ b/tests/baselines/reference/destructuringArrayBindingPatternAndAssignment5.types
@@ -46,55 +46,6 @@ function f1() {
>a4 : number
>1 : 1
>[1] : [number]
->1 : 1
-
- function fn1([a1, b1 = a1] = [1]) { };
->fn1 : ([a1, b1]?: [number, any?]) => void
->a1 : number
->b1 : any
->a1 : number
->[1] : [number]
->1 : 1
-
- function fn2([a2, b2 = 1 + a2] = [1]) { };
->fn2 : ([a2, b2]?: [number, any?]) => void
->a2 : number
->b2 : any
->1 + a2 : number
->1 : 1
->a2 : number
->[1] : [number]
->1 : 1
-
- function fn3([a3, b3 = (() => 1 + a3)()] = [1]) { };
->fn3 : ([a3, b3]?: [number, any?]) => void
->a3 : number
->b3 : any
->(() => 1 + a3)() : number
->(() => 1 + a3) : () => number
->() => 1 + a3 : () => number
->1 + a3 : number
->1 : 1
->a3 : number
->[1] : [number]
->1 : 1
-
- function fn4([a4, b4 = (() => (() => 1 + a4)() + 1)()] = [1]) { };
->fn4 : ([a4, b4]?: [number, any?]) => void
->a4 : number
->b4 : any
->(() => (() => 1 + a4)() + 1)() : number
->(() => (() => 1 + a4)() + 1) : () => number
->() => (() => 1 + a4)() + 1 : () => number
->(() => 1 + a4)() + 1 : number
->(() => 1 + a4)() : number
->(() => 1 + a4) : () => number
->() => 1 + a4 : () => number
->1 + a4 : number
->1 : 1
->a4 : number
->1 : 1
->[1] : [number]
>1 : 1
}
diff --git a/tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAssignment5.ts b/tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAssignment5.ts
index b14b985..dc748a6 100644
--- a/tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAssignment5.ts
+++ b/tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAssignment5.ts
@@ -1,3 +1,5 @@
+// @noImplicitAny: true
+
// To be inferred as `number`
function f1() {
const [a1, b1 = a1] = [1];
@babakks
Babak K. Shandiz (babakks) marked this pull request as ready for review August 9, 2022 21:17
Signed-off-by: Babak K. Shandiz <babak.k.shandiz@gmail.com>
>b : any
>a : any
>a : string
>b : string | number

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this probably could be improved as it's impossible for b to be of type string here. Perhaps this doesn't have to be improved in this PR though and a followup issue could be created to track this.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally agree.

@andrewbranch

Copy link
Copy Markdown
Member

@typescript-bot

TypeScript Bot (typescript-bot) commented Aug 19, 2022

Copy link
Copy Markdown
Contributor

Heya Andrew Branch (@andrewbranch), I've started to run the perf test suite on this PR at 84b0110. You can monitor the build here.

Update: The results are in!

@typescript-bot

TypeScript Bot (typescript-bot) commented Aug 19, 2022

Copy link
Copy Markdown
Contributor

Heya Andrew Branch (@andrewbranch), I've started to run the tarball bundle task on this PR at 84b0110. You can monitor the build here.

@andrewbranch

Andrew Branch (andrewbranch) commented Aug 19, 2022

Copy link
Copy Markdown
Member

I haven’t checked yet, but I believe this might break this case:

const[a,b=()=>a]=[0]

I doubt that eagerly checking for circularities by syntax/symbol is going to be a workable approach because of cases like this. I think this example works today only because checking function bodies is a deferred operation, which may provide a hint for an alternative approach, but I’m really not sure. You can also imagine cases where a is referenced in b’s initializer but not in any way that contributes to the type, e.g.

const[a,b=(a,0)]=[0];// errors todayconst[c,d=()=>{console.log(c);return0;}]=[0];// ok

Are you sure that this code path doesn’t just need to pass reportErrors as false (or propagate that down into further checks, if it already is false)? If we’re just trying to get a contextual type for the variable declaration initializer, it doesn’t seem like errors should be reported. What is the call stack when the implicit any error is reported?

@typescript-bot

TypeScript Bot (typescript-bot) commented Aug 19, 2022

Copy link
Copy Markdown
Contributor

Hey Andrew Branch (@andrewbranch), I've packed this into an installable tgz. You can install it for testing by referencing it in your package.json like so:

{
"devDependencies": {
"typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/132317/artifacts?artifactName=tgz&fileId=EAB9E2731D1701C30D1519BEC0016F665A845A22DD20C9C02A568E34197F338702&fileName=/typescript-4.9.0-insiders.20220819.tgz"
}
}

and then running npm install.


There is also a playground for this build and an npm module you can use via "typescript": "npm:@typescript-deploys/pr-build@4.9.0-pr-50241-4".;

@andrewbranch

Copy link
Copy Markdown
Member

It looks like the examples I mentioned still work in your PR—but that really still makes me think it should just be possible to squash the error without doing the eager circularity check.

@typescript-bot

Copy link
Copy Markdown
Contributor

Andrew Branch (@andrewbranch)
The results of the perf run you requested are in!

Here they are:

Compiler

Comparison Report - main..50241
Metricmain50241DeltaBestWorst
Angular - node (v10.16.3, x64)
Memory used361,602k (± 0.02%)361,626k (± 0.02%)+23k (+ 0.01%)361,471k361,865k
Parse Time2.11s (± 0.63%)2.10s (± 0.67%)-0.01s (- 0.47%)2.08s2.13s
Bind Time0.90s (± 0.53%)0.90s (± 0.58%)-0.00s (- 0.44%)0.89s0.91s
Check Time6.10s (± 0.55%)6.06s (± 0.39%)-0.04s (- 0.62%)6.02s6.11s
Emit Time6.07s (± 0.88%)6.00s (± 0.67%)-0.07s (- 1.22%)5.91s6.08s
Total Time15.18s (± 0.48%)15.05s (± 0.34%)-0.13s (- 0.84%)14.96s15.18s
Compiler-Unions - node (v10.16.3, x64)
Memory used205,801k (± 0.03%)205,724k (± 0.04%)-76k (- 0.04%)205,518k205,940k
Parse Time0.83s (± 0.74%)0.83s (± 0.96%)+0.00s (+ 0.12%)0.81s0.85s
Bind Time0.53s (± 1.69%)0.52s (± 1.11%)-0.00s (- 0.57%)0.51s0.54s
Check Time7.39s (± 0.40%)7.37s (± 0.85%)-0.02s (- 0.30%)7.23s7.55s
Emit Time2.41s (± 0.85%)2.42s (± 0.84%)+0.01s (+ 0.41%)2.37s2.47s
Total Time11.17s (± 0.24%)11.15s (± 0.56%)-0.02s (- 0.19%)11.04s11.31s
Monaco - node (v10.16.3, x64)
Memory used344,139k (± 0.02%)344,172k (± 0.02%)+34k (+ 0.01%)344,054k344,352k
Parse Time1.60s (± 0.63%)1.61s (± 0.41%)+0.01s (+ 0.31%)1.60s1.63s
Bind Time0.76s (± 0.90%)0.76s (± 1.16%)+0.00s (+ 0.53%)0.74s0.77s
Check Time6.01s (± 0.47%)5.99s (± 0.59%)-0.02s (- 0.32%)5.89s6.06s
Emit Time3.24s (± 0.52%)3.23s (± 0.56%)-0.01s (- 0.31%)3.18s3.25s
Total Time11.61s (± 0.40%)11.59s (± 0.42%)-0.02s (- 0.18%)11.47s11.68s
TFS - node (v10.16.3, x64)
Memory used305,267k (± 0.02%)305,268k (± 0.02%)+1k (+ 0.00%)305,060k305,389k
Parse Time1.30s (± 0.76%)1.29s (± 0.43%)-0.01s (- 0.46%)1.28s1.30s
Bind Time0.72s (± 0.68%)0.72s (± 0.77%)-0.00s (- 0.28%)0.71s0.73s
Check Time5.47s (± 0.43%)5.46s (± 0.23%)-0.01s (- 0.22%)5.43s5.49s
Emit Time3.42s (± 0.58%)3.38s (± 0.95%)-0.04s (- 1.14%)3.31s3.47s
Total Time10.91s (± 0.33%)10.85s (± 0.34%)-0.06s (- 0.54%)10.77s10.94s
material-ui - node (v10.16.3, x64)
Memory used472,873k (± 0.01%)472,882k (± 0.02%)+9k (+ 0.00%)472,727k473,032k
Parse Time1.83s (± 0.83%)1.85s (± 0.67%)+0.01s (+ 0.82%)1.83s1.89s
Bind Time0.68s (± 1.00%)0.68s (± 1.72%)-0.00s (- 0.44%)0.66s0.70s
Check Time14.61s (± 0.91%)14.67s (± 0.58%)+0.06s (+ 0.41%)14.42s14.83s
Emit Time0.00s (± 0.00%)0.00s (± 0.00%)0.00s ( NaN%)0.00s0.00s
Total Time17.12s (± 0.84%)17.20s (± 0.56%)+0.07s (+ 0.43%)16.92s17.38s
xstate - node (v10.16.3, x64)
Memory used582,739k (± 0.02%)582,761k (± 0.01%)+22k (+ 0.00%)582,639k582,952k
Parse Time2.61s (± 0.40%)2.61s (± 0.45%)-0.00s (- 0.11%)2.59s2.64s
Bind Time1.05s (± 0.97%)1.04s (± 1.06%)-0.01s (- 0.86%)1.02s1.07s
Check Time1.57s (± 0.82%)1.57s (± 0.92%)-0.00s (- 0.13%)1.54s1.59s
Emit Time0.07s (± 4.66%)0.07s (± 3.14%)-0.00s (- 2.74%)0.07s0.08s
Total Time5.30s (± 0.40%)5.28s (± 0.53%)-0.02s (- 0.40%)5.23s5.36s
Angular - node (v12.1.0, x64)
Memory used339,129k (± 0.02%)339,136k (± 0.02%)+8k (+ 0.00%)338,924k339,293k
Parse Time2.08s (± 0.61%)2.10s (± 0.55%)+0.01s (+ 0.67%)2.07s2.12s
Bind Time0.86s (± 1.10%)0.86s (± 0.90%)+0.00s (+ 0.47%)0.85s0.88s
Check Time5.85s (± 0.49%)5.87s (± 0.50%)+0.01s (+ 0.17%)5.81s5.93s
Emit Time6.24s (± 0.82%)6.21s (± 0.63%)-0.03s (- 0.43%)6.12s6.34s
Total Time15.03s (± 0.47%)15.03s (± 0.39%)+0.00s (+ 0.01%)14.88s15.16s
Compiler-Unions - node (v12.1.0, x64)
Memory used193,494k (± 0.04%)193,400k (± 0.14%)-95k (- 0.05%)192,351k193,705k
Parse Time0.82s (± 0.83%)0.83s (± 0.70%)+0.00s (+ 0.36%)0.81s0.84s
Bind Time0.55s (± 1.08%)0.56s (± 0.85%)+0.00s (+ 0.36%)0.55s0.57s
Check Time6.95s (± 0.52%)6.94s (± 0.51%)-0.01s (- 0.13%)6.85s7.02s
Emit Time2.46s (± 1.10%)2.49s (± 1.38%)+0.04s (+ 1.51%)2.43s2.59s
Total Time10.78s (± 0.49%)10.81s (± 0.57%)+0.03s (+ 0.32%)10.67s11.00s
Monaco - node (v12.1.0, x64)
Memory used327,074k (± 0.02%)327,128k (± 0.01%)+54k (+ 0.02%)327,026k327,193k
Parse Time1.58s (± 0.83%)1.58s (± 0.71%)0.00s ( 0.00%)1.56s1.61s
Bind Time0.74s (± 1.14%)0.75s (± 0.91%)+0.01s (+ 0.67%)0.74s0.77s
Check Time5.82s (± 0.36%)5.84s (± 0.43%)+0.02s (+ 0.40%)5.80s5.92s
Emit Time3.27s (± 0.73%)3.29s (± 0.89%)+0.02s (+ 0.49%)3.25s3.38s
Total Time11.42s (± 0.34%)11.46s (± 0.45%)+0.04s (+ 0.35%)11.40s11.60s
TFS - node (v12.1.0, x64)
Memory used289,891k (± 0.02%)289,829k (± 0.05%)-61k (- 0.02%)289,305k290,028k
Parse Time1.30s (± 0.78%)1.30s (± 0.54%)0.00s ( 0.00%)1.29s1.32s
Bind Time0.72s (± 1.17%)0.72s (± 0.65%)-0.00s (- 0.14%)0.71s0.73s
Check Time5.38s (± 0.32%)5.40s (± 0.70%)+0.02s (+ 0.39%)5.33s5.50s
Emit Time3.47s (± 1.13%)3.52s (± 1.80%)+0.05s (+ 1.44%)3.39s3.73s
Total Time10.87s (± 0.45%)10.94s (± 0.90%)+0.07s (+ 0.62%)10.77s11.26s
material-ui - node (v12.1.0, x64)
Memory used452,020k (± 0.01%)452,063k (± 0.01%)+44k (+ 0.01%)451,890k452,187k
Parse Time1.84s (± 1.43%)1.84s (± 0.63%)-0.00s (- 0.16%)1.82s1.87s
Bind Time0.67s (± 2.10%)0.68s (± 1.45%)+0.00s (+ 0.59%)0.66s0.70s
Check Time13.22s (± 0.47%)13.17s (± 0.62%)-0.05s (- 0.39%)12.97s13.35s
Emit Time0.00s (± 0.00%)0.00s (± 0.00%)0.00s ( NaN%)0.00s0.00s
Total Time15.73s (± 0.53%)15.68s (± 0.55%)-0.05s (- 0.30%)15.48s15.91s
xstate - node (v12.1.0, x64)
Memory used554,320k (± 1.74%)547,834k (± 0.01%)-6,486k (- 1.17%)547,726k547,951k
Parse Time2.54s (± 0.61%)2.54s (± 0.58%)+0.01s (+ 0.20%)2.51s2.59s
Bind Time1.03s (± 1.21%)1.03s (± 0.90%)-0.00s (- 0.19%)1.01s1.05s
Check Time1.51s (± 0.38%)1.51s (± 0.59%)+0.00s (+ 0.07%)1.49s1.53s
Emit Time0.07s (± 0.00%)0.07s (± 0.00%)0.00s ( 0.00%)0.07s0.07s
Total Time5.15s (± 0.48%)5.16s (± 0.35%)+0.01s (+ 0.14%)5.10s5.19s
Angular - node (v14.15.1, x64)
Memory used337,152k (± 0.01%)337,160k (± 0.01%)+8k (+ 0.00%)337,103k337,208k
Parse Time2.07s (± 0.42%)2.07s (± 0.60%)-0.00s (- 0.24%)2.04s2.10s
Bind Time0.90s (± 0.86%)0.90s (± 0.53%)-0.00s (- 0.44%)0.89s0.91s
Check Time5.88s (± 0.48%)5.85s (± 0.41%)-0.02s (- 0.41%)5.79s5.90s
Emit Time6.21s (± 0.50%)6.23s (± 1.01%)+0.02s (+ 0.37%)6.10s6.37s
Total Time15.06s (± 0.22%)15.04s (± 0.45%)-0.01s (- 0.08%)14.90s15.24s
Compiler-Unions - node (v14.15.1, x64)
Memory used192,021k (± 0.02%)192,026k (± 0.02%)+5k (+ 0.00%)191,939k192,101k
Parse Time0.85s (± 0.87%)0.85s (± 0.56%)-0.00s (- 0.00%)0.84s0.86s
Bind Time0.58s (± 0.69%)0.58s (± 0.69%)-0.00s (- 0.00%)0.57s0.59s
Check Time6.93s (± 0.42%)6.95s (± 0.55%)+0.01s (+ 0.22%)6.84s7.01s
Emit Time2.41s (± 0.70%)2.43s (± 0.81%)+0.02s (+ 0.87%)2.40s2.48s
Total Time10.78s (± 0.34%)10.81s (± 0.46%)+0.03s (+ 0.30%)10.67s10.89s
Monaco - node (v14.15.1, x64)
Memory used325,915k (± 0.00%)325,904k (± 0.01%)-11k (- 0.00%)325,871k325,951k
Parse Time1.58s (± 1.01%)1.57s (± 0.58%)-0.01s (- 0.44%)1.56s1.59s
Bind Time0.78s (± 0.96%)0.77s (± 0.64%)-0.00s (- 0.39%)0.77s0.79s
Check Time5.71s (± 0.63%)5.69s (± 0.64%)-0.03s (- 0.44%)5.62s5.78s
Emit Time3.34s (± 0.92%)3.34s (± 0.61%)-0.00s (- 0.06%)3.29s3.37s
Total Time11.40s (± 0.50%)11.37s (± 0.49%)-0.03s (- 0.29%)11.26s11.50s
TFS - node (v14.15.1, x64)
Memory used288,957k (± 0.01%)288,977k (± 0.01%)+20k (+ 0.01%)288,940k289,023k
Parse Time1.33s (± 1.79%)1.33s (± 1.41%)+0.00s (+ 0.23%)1.29s1.37s
Bind Time0.77s (± 4.71%)0.77s (± 4.57%)-0.00s (- 0.13%)0.73s0.86s
Check Time5.38s (± 0.64%)5.38s (± 0.40%)-0.00s (- 0.02%)5.34s5.42s
Emit Time3.60s (± 0.80%)3.57s (± 1.86%)-0.04s (- 1.05%)3.43s3.66s
Total Time11.09s (± 0.49%)11.05s (± 0.60%)-0.04s (- 0.33%)10.88s11.18s
material-ui - node (v14.15.1, x64)
Memory used450,317k (± 0.01%)450,317k (± 0.00%)0k ( 0.00%)450,283k450,367k
Parse Time1.88s (± 0.31%)1.89s (± 0.40%)+0.01s (+ 0.53%)1.87s1.90s
Bind Time0.71s (± 0.83%)0.72s (± 0.97%)+0.01s (+ 0.70%)0.71s0.73s
Check Time13.23s (± 0.63%)13.24s (± 0.77%)+0.01s (+ 0.10%)13.07s13.45s
Emit Time0.00s (± 0.00%)0.00s (± 0.00%)0.00s ( NaN%)0.00s0.00s
Total Time15.83s (± 0.52%)15.85s (± 0.68%)+0.03s (+ 0.18%)15.68s16.06s
xstate - node (v14.15.1, x64)
Memory used545,608k (± 0.00%)545,649k (± 0.00%)+41k (+ 0.01%)545,595k545,707k
Parse Time2.61s (± 0.48%)2.60s (± 0.42%)-0.01s (- 0.31%)2.58s2.64s
Bind Time1.16s (± 1.23%)1.16s (± 0.66%)0.00s ( 0.00%)1.14s1.17s
Check Time1.56s (± 0.43%)1.56s (± 0.53%)+0.01s (+ 0.45%)1.55s1.58s
Emit Time0.07s (± 4.66%)0.07s (± 4.92%)+0.00s (+ 1.37%)0.07s0.08s
Total Time5.39s (± 0.39%)5.39s (± 0.24%)+0.00s (+ 0.09%)5.36s5.43s
System
Machine Namets-ci-ubuntu
Platformlinux 4.4.0-210-generic
Architecturex64
Available Memory16 GB
Available Memory15 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v10.16.3, x64)
  • node (v12.1.0, x64)
  • node (v14.15.1, x64)
Scenarios
  • Angular - node (v10.16.3, x64)
  • Angular - node (v12.1.0, x64)
  • Angular - node (v14.15.1, x64)
  • Compiler-Unions - node (v10.16.3, x64)
  • Compiler-Unions - node (v12.1.0, x64)
  • Compiler-Unions - node (v14.15.1, x64)
  • Monaco - node (v10.16.3, x64)
  • Monaco - node (v12.1.0, x64)
  • Monaco - node (v14.15.1, x64)
  • TFS - node (v10.16.3, x64)
  • TFS - node (v12.1.0, x64)
  • TFS - node (v14.15.1, x64)
  • material-ui - node (v10.16.3, x64)
  • material-ui - node (v12.1.0, x64)
  • material-ui - node (v14.15.1, x64)
  • xstate - node (v10.16.3, x64)
  • xstate - node (v12.1.0, x64)
  • xstate - node (v14.15.1, x64)
BenchmarkNameIterations
Current5024110
Baselinemain10

TSServer

Comparison Report - main..50241
Metricmain50241DeltaBestWorst
Compiler-UnionsTSServer - node (v10.16.3, x64)
Req 1 - updateOpen1,464ms (± 0.42%)1,458ms (± 0.62%)-6ms (- 0.42%)1,439ms1,481ms
Req 2 - geterr3,810ms (± 0.43%)3,787ms (± 0.55%)-23ms (- 0.60%)3,738ms3,822ms
Req 3 - references279ms (± 0.81%)278ms (± 0.97%)-1ms (- 0.32%)274ms287ms
Req 4 - navto230ms (± 2.28%)233ms (± 0.85%)+3ms (+ 1.22%)229ms238ms
Req 5 - completionInfo count1,355 (± 0.00%)1,355 (± 0.00%)0 ( 0.00%)1,3551,355
Req 5 - completionInfo64ms (± 4.32%)65ms (± 4.23%)+2ms (+ 2.35%)59ms72ms
CompilerTSServer - node (v10.16.3, x64)
Req 1 - updateOpen1,568ms (± 0.64%)1,566ms (± 0.48%)-1ms (- 0.08%)1,554ms1,586ms
Req 2 - geterr2,278ms (± 0.71%)2,288ms (± 1.17%)+10ms (+ 0.44%)2,249ms2,389ms
Req 3 - references298ms (± 1.59%)303ms (± 2.55%)+5ms (+ 1.54%)295ms331ms
Req 4 - navto234ms (± 2.52%)236ms (± 2.16%)+2ms (+ 0.64%)226ms244ms
Req 5 - completionInfo count1,517 (± 0.00%)1,517 (± 0.00%)0 ( 0.00%)1,5171,517
Req 5 - completionInfo69ms (± 1.72%)70ms (± 1.11%)+1ms (+ 1.01%)68ms72ms
xstateTSServer - node (v10.16.3, x64)
Req 1 - updateOpen2,177ms (± 0.64%)2,196ms (± 0.43%)+19ms (+ 0.87%)2,179ms2,226ms
Req 2 - geterr777ms (± 0.51%)778ms (± 0.45%)+1ms (+ 0.12%)771ms787ms
Req 3 - references102ms (± 1.70%)100ms (± 1.35%)-2ms (- 1.48%)97ms104ms
Req 4 - navto251ms (± 1.49%)253ms (± 0.78%)+2ms (+ 0.96%)248ms257ms
Req 5 - completionInfo count3,293 (± 0.00%)3,293 (± 0.00%)0 ( 0.00%)3,2933,293
Req 5 - completionInfo272ms (± 1.07%)270ms (± 1.27%)-2ms (- 0.70%)265ms281ms
Compiler-UnionsTSServer - node (v12.1.0, x64)
Req 1 - updateOpen1,498ms (± 0.67%)1,484ms (± 0.61%)-14ms (- 0.93%)1,467ms1,506ms
Req 2 - geterr3,559ms (± 0.69%)3,562ms (± 0.76%)+3ms (+ 0.09%)3,502ms3,624ms
Req 3 - references263ms (± 0.74%)264ms (± 1.07%)+1ms (+ 0.49%)259ms272ms
Req 4 - navto207ms (± 1.24%)206ms (± 1.38%)-1ms (- 0.29%)202ms214ms
Req 5 - completionInfo count1,355 (± 0.00%)1,355 (± 0.00%)0 ( 0.00%)1,3551,355
Req 5 - completionInfo78ms (±12.61%)74ms (±17.39%)🟩-4ms (- 4.50%)55ms99ms
CompilerTSServer - node (v12.1.0, x64)
Req 1 - updateOpen1,569ms (± 0.66%)1,573ms (± 0.95%)+5ms (+ 0.29%)1,542ms1,624ms
Req 2 - geterr2,222ms (± 0.40%)2,221ms (± 0.54%)-1ms (- 0.04%)2,191ms2,254ms
Req 3 - references275ms (± 0.42%)274ms (± 0.75%)-1ms (- 0.18%)269ms277ms
Req 4 - navto215ms (± 1.11%)215ms (± 0.97%)-1ms (- 0.23%)212ms220ms
Req 5 - completionInfo count1,517 (± 0.00%)1,517 (± 0.00%)0 ( 0.00%)1,5171,517
Req 5 - completionInfo62ms (± 3.55%)64ms (± 2.87%)+3ms (+ 4.39%)60ms67ms
xstateTSServer - node (v12.1.0, x64)
Req 1 - updateOpen2,128ms (± 0.58%)2,127ms (± 0.48%)-1ms (- 0.02%)2,107ms2,157ms
Req 2 - geterr754ms (± 0.60%)757ms (± 0.58%)+2ms (+ 0.32%)749ms770ms
Req 3 - references68ms (± 1.32%)68ms (± 1.20%)+0ms (+ 0.59%)66ms70ms
Req 4 - navto240ms (± 1.26%)239ms (± 1.91%)-1ms (- 0.46%)229ms251ms
Req 5 - completionInfo count3,293 (± 0.00%)3,293 (± 0.00%)0 ( 0.00%)3,2933,293
Req 5 - completionInfo267ms (± 0.73%)268ms (± 0.61%)+1ms (+ 0.26%)264ms271ms
Compiler-UnionsTSServer - node (v14.15.1, x64)
Req 1 - updateOpen1,543ms (± 0.27%)1,538ms (± 0.65%)-5ms (- 0.32%)1,519ms1,568ms
Req 2 - geterr3,687ms (± 0.72%)3,685ms (± 0.61%)-1ms (- 0.04%)3,638ms3,753ms
Req 3 - references278ms (± 0.75%)278ms (± 0.88%)+0ms (+ 0.07%)274ms283ms
Req 4 - navto220ms (± 0.75%)219ms (± 0.65%)-1ms (- 0.59%)217ms222ms
Req 5 - completionInfo count1,355 (± 0.00%)1,355 (± 0.00%)0 ( 0.00%)1,3551,355
Req 5 - completionInfo58ms (± 5.58%)55ms (± 1.65%)🟩-3ms (- 4.52%)53ms57ms
CompilerTSServer - node (v14.15.1, x64)
Req 1 - updateOpen1,608ms (± 0.69%)1,606ms (± 0.32%)-2ms (- 0.12%)1,591ms1,615ms
Req 2 - geterr2,344ms (± 0.45%)2,348ms (± 0.61%)+4ms (+ 0.18%)2,319ms2,377ms
Req 3 - references287ms (± 1.15%)290ms (± 1.65%)+3ms (+ 1.01%)283ms298ms
Req 4 - navto235ms (± 2.22%)232ms (± 2.63%)-2ms (- 0.90%)225ms249ms
Req 5 - completionInfo count1,517 (± 0.00%)1,517 (± 0.00%)0 ( 0.00%)1,5171,517
Req 5 - completionInfo53ms (± 1.25%)53ms (± 1.40%)-0ms (- 0.56%)52ms55ms
xstateTSServer - node (v14.15.1, x64)
Req 1 - updateOpen2,224ms (± 0.47%)2,231ms (± 0.41%)+7ms (+ 0.29%)2,211ms2,249ms
Req 2 - geterr778ms (± 0.38%)783ms (± 0.37%)+5ms (+ 0.60%)776ms790ms
Req 3 - references66ms (± 1.06%)67ms (± 0.89%)+1ms (+ 0.76%)65ms68ms
Req 4 - navto245ms (± 1.13%)248ms (± 0.93%)+3ms (+ 1.26%)244ms255ms
Req 5 - completionInfo count3,293 (± 0.00%)3,293 (± 0.00%)0 ( 0.00%)3,2933,293
Req 5 - completionInfo271ms (± 0.74%)274ms (± 0.46%)+2ms (+ 0.89%)270ms276ms
System
Machine Namets-ci-ubuntu
Platformlinux 4.4.0-210-generic
Architecturex64
Available Memory16 GB
Available Memory15 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v10.16.3, x64)
  • node (v12.1.0, x64)
  • node (v14.15.1, x64)
Scenarios
  • Compiler-UnionsTSServer - node (v10.16.3, x64)
  • Compiler-UnionsTSServer - node (v12.1.0, x64)
  • Compiler-UnionsTSServer - node (v14.15.1, x64)
  • CompilerTSServer - node (v10.16.3, x64)
  • CompilerTSServer - node (v12.1.0, x64)
  • CompilerTSServer - node (v14.15.1, x64)
  • xstateTSServer - node (v10.16.3, x64)
  • xstateTSServer - node (v12.1.0, x64)
  • xstateTSServer - node (v14.15.1, x64)
BenchmarkNameIterations
Current5024110
Baselinemain10

Developer Information:

Download Benchmark

@babakks

Copy link
Copy Markdown
ContributorAuthor

Andrew Branch (@andrewbranch) Thanks for the hints. Actually, this wasn't my first approach. I was looking for some way to suppress type-checking errors by propagating reportErrors just as you said, but, unfortunately, it'd go deep into a good number of methods. To be more specific, to propagate reportErrors argument, we have to add it as a parameter to the checkExpression and also other type-check methods called from that on (e.g., checkIdentifier in the example below). Obviously, changing the signature for all those methods wasn't a good solution. Neither defining a new state variable accessible to all those methods would incur other statefulness problems/corner cases. So, I tried to eliminate the unnecessary type-check with a rather repressive, ad-hoc approach which you see in this PR.

Below is the stack trace from the getTypeFromBindingElement down to the point where we wrongly push the symbol onto the type-checking stack (which shouldn't happen since we don't want to report errors yet). This session has been run on an existing test involving binding elements (i.e., destructuringArrayBindingPatternAndAssignment3.ts) on the main branch (at 9767f51):

const[a,b=a]=[1];// ok
...

As in the stack trace, there are 3 important points (marked with asterisks):

  • The first one (*) is when the getTypeFromBindingElement method is called for the first time (I mean called on the second binding element, b = a) and reportErrors is expectedly set to false.
  • The second one (**) where getTypeFromBindingElement is called again (on the b = a element) with reportErrors = false.
  • The last one (***) on the top line of the stack trace is where we pushed the symbol a on the type-checking stack, which shouldn't happen since we don't want errors reported.

With this PR, just the first call happens, and then the type checking returns with any.

Stack trace

*** at pushTypeResolution (/workspaces/TypeScript/built/local/run.js:56208:45)
at getTypeOfVariableOrParameterOrPropertyWorker (/workspaces/TypeScript/built/local/run.js:57181:18)
at getTypeOfVariableOrParameterOrProperty (/workspaces/TypeScript/built/local/run.js:57121:28)
at getTypeOfSymbol (/workspaces/TypeScript/built/local/run.js:57493:24)
at getNarrowedTypeOfSymbol (/workspaces/TypeScript/built/local/run.js:72421:20)
at checkIdentifier (/workspaces/TypeScript/built/local/run.js:72497:24)
at checkExpressionWorker (/workspaces/TypeScript/built/local/run.js:80745:28)
at checkExpression (/workspaces/TypeScript/built/local/run.js:80694:38)
at checkExpressionWithContextualType (/workspaces/TypeScript/built/local/run.js:80324:28)
at checkDeclarationInitializer (/workspaces/TypeScript/built/local/run.js:80374:21)
** at getTypeFromBindingElement (/workspaces/TypeScript/built/local/run.js:56990:81)
at /workspaces/TypeScript/built/local/run.js:57040:109
at [Object.map](http://object.map/) (/workspaces/TypeScript/built/local/run.js:455:29)
at getTypeFromArrayBindingPattern (/workspaces/TypeScript/built/local/run.js:57040:35)
at getTypeFromBindingPattern (/workspaces/TypeScript/built/local/run.js:57063:19)
at getContextualTypeForInitializerExpression (/workspaces/TypeScript/built/local/run.js:73283:28)
at getContextualType (/workspaces/TypeScript/built/local/run.js:73808:28)
at getApparentTypeOfContextualType (/workspaces/TypeScript/built/local/run.js:73727:17)
at checkArrayLiteral (/workspaces/TypeScript/built/local/run.js:74170:34)
at checkExpressionWorker (/workspaces/TypeScript/built/local/run.js:80775:28)
at checkExpression (/workspaces/TypeScript/built/local/run.js:80694:38)
at checkExpressionCached (/workspaces/TypeScript/built/local/run.js:80358:38)
at checkDeclarationInitializer (/workspaces/TypeScript/built/local/run.js:80375:23)
at getTypeForVariableLikeDeclaration (/workspaces/TypeScript/built/local/run.js:56604:74)
at getTypeForBindingElementParent (/workspaces/TypeScript/built/local/run.js:56312:61)
at getNarrowedTypeOfSymbol (/workspaces/TypeScript/built/local/run.js:72373:46)
at checkIdentifier (/workspaces/TypeScript/built/local/run.js:72497:24)
at checkExpressionWorker (/workspaces/TypeScript/built/local/run.js:80745:28)
at checkExpression (/workspaces/TypeScript/built/local/run.js:80694:38)
at checkExpressionWithContextualType (/workspaces/TypeScript/built/local/run.js:80324:28)
at checkDeclarationInitializer (/workspaces/TypeScript/built/local/run.js:80374:21)
* at getTypeFromBindingElement (/workspaces/TypeScript/built/local/run.js:56990:81)
at /workspaces/TypeScript/built/local/run.js:57040:109
at [Object.map](http://object.map/) (/workspaces/TypeScript/built/local/run.js:455:29)
at getTypeFromArrayBindingPattern (/workspaces/TypeScript/built/local/run.js:57040:35)
at getTypeFromBindingPattern (/workspaces/TypeScript/built/local/run.js:57063:19)
at getContextualTypeForInitializerExpression (/workspaces/TypeScript/built/local/run.js:73283:28)
at getContextualType (/workspaces/TypeScript/built/local/run.js:73808:28)
at getApparentTypeOfContextualType (/workspaces/TypeScript/built/local/run.js:73727:17)
at checkArrayLiteral (/workspaces/TypeScript/built/local/run.js:74170:34)
at checkExpressionWorker (/workspaces/TypeScript/built/local/run.js:80775:28)
at checkExpression (/workspaces/TypeScript/built/local/run.js:80694:38)
at checkExpressionCached (/workspaces/TypeScript/built/local/run.js:80358:38)
at checkDeclarationInitializer (/workspaces/TypeScript/built/local/run.js:80375:23)
at getTypeForVariableLikeDeclaration (/workspaces/TypeScript/built/local/run.js:56604:74)
at getTypeForBindingElementParent (/workspaces/TypeScript/built/local/run.js:56312:61)
at checkVariableLikeDeclaration (/workspaces/TypeScript/built/local/run.js:83464:34)
at checkBindingElement (/workspaces/TypeScript/built/local/run.js:83605:20)
at checkSourceElementWorker (/workspaces/TypeScript/built/local/run.js:86814:28)
at checkSourceElement (/workspaces/TypeScript/built/local/run.js:86643:17)
at Object.forEach (/workspaces/TypeScript/built/local/run.js:186:30)
at checkVariableLikeDeclaration (/workspaces/TypeScript/built/local/run.js:83483:20)
at checkVariableDeclaration (/workspaces/TypeScript/built/local/run.js:83600:13)
at checkSourceElementWorker (/workspaces/TypeScript/built/local/run.js:86812:28)
at checkSourceElement (/workspaces/TypeScript/built/local/run.js:86643:17)
at Object.forEach (/workspaces/TypeScript/built/local/run.js:186:30)
at checkVariableStatement (/workspaces/TypeScript/built/local/run.js:83611:16)
at checkSourceElementWorker (/workspaces/TypeScript/built/local/run.js:86781:28)
at checkSourceElement (/workspaces/TypeScript/built/local/run.js:86643:17)
at Object.forEach (/workspaces/TypeScript/built/local/run.js:186:30)
at checkSourceFileWorker (/workspaces/TypeScript/built/local/run.js:87018:20)
at checkSourceFile (/workspaces/TypeScript/built/local/run.js:86983:13)
at checkSourceFileWithEagerDiagnostics (/workspaces/TypeScript/built/local/run.js:87093:13)
at getDiagnosticsWorker (/workspaces/TypeScript/built/local/run.js:87104:17)
at Object.getDiagnostics (/workspaces/TypeScript/built/local/run.js:87070:24)
at /workspaces/TypeScript/built/local/run.js:119101:85
at runWithCancellationToken (/workspaces/TypeScript/built/local/run.js:119066:24)
at getBindAndCheckDiagnosticsForFileNoCache (/workspaces/TypeScript/built/local/run.js:119084:20)
at getAndCacheDiagnostics (/workspaces/TypeScript/built/local/run.js:119380:26)
at getBindAndCheckDiagnosticsForFile (/workspaces/TypeScript/built/local/run.js:119081:20)
at getSemanticDiagnosticsForFile (/workspaces/TypeScript/built/local/run.js:119078:61)
at /workspaces/TypeScript/built/local/run.js:119014:24
at Object.flatMap (/workspaces/TypeScript/built/local/run.js:519:25)
at getDiagnosticsHelper (/workspaces/TypeScript/built/local/run.js:119010:56)
at Object.getSemanticDiagnostics (/workspaces/TypeScript/built/local/run.js:119021:20)
at Object.getPreEmitDiagnostics (/workspaces/TypeScript/built/local/run.js:117432:56)
at Object.compileFiles (/workspaces/TypeScript/built/local/run.js:187832:42)
at Object.compileFiles (/workspaces/TypeScript/built/local/run.js:190656:35)
at new CompilerTest (/workspaces/TypeScript/built/local/run.js:200025:44)
at Context.<anonymous> (/workspaces/TypeScript/built/local/run.js:199923:32)
at callFn (/workspaces/TypeScript/node_modules/mocha/lib/runnable.js:366:21)
at [Hook.run](http://hook.run/) (/workspaces/TypeScript/node_modules/mocha/lib/runnable.js:354:5)
at next (/workspaces/TypeScript/node_modules/mocha/lib/runner.js:498:10)
at Immediate._onImmediate (/workspaces/TypeScript/node_modules/mocha/lib/runner.js:559:5)
at processImmediate (internal/timers.js:464:21)
at process.callbackTrampoline (internal/async_hooks.js:130:17)'

@babakks

Babak K. Shandiz (babakks) commented Aug 22, 2022

Copy link
Copy Markdown
ContributorAuthor

Andrew Branch (@andrewbranch) Could defining a new CheckMode value be a good idea? 🤔

@andrewbranch

Copy link
Copy Markdown
Member

Babak K. Shandiz (@babakks)Wesley Wigham (@weswigham) speculated that probably only CheckMode.Normal should issue errors, so maybe you don’t even need a new one.

@Andarist

Mateusz Burzyński (Andarist) commented Aug 23, 2022

Copy link
Copy Markdown
Contributor

I gotta say - I love your extensive descriptions/notes here, Babak K. Shandiz (@babakks) ❤️

@babakks

Copy link
Copy Markdown
ContributorAuthor

Andrew Branch (@andrewbranch) I've submitted another PR with the CheckMode utilization approach. Could you please review it anytime?

@andrewbranch

Copy link
Copy Markdown
Member

Looks like this was abandoned in favor of #56753

@babakks
Babak K. Shandiz (babakks) deleted the improve-binding-element-type-inference branch May 24, 2024 00:06
@microsoftMicrosoft (microsoft) locked as resolved and limited conversation to collaborators Oct 16, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

For Backlog BugPRs that fix a backlog bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Using variable defined by array destructuring assignment in default value of variables defined afterwards.

5 participants

@babakks@andrewbranch@typescript-bot@Andarist@sandersn