Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve binding element type inference #50241

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

babakks
Copy link
Contributor

@babakks babakks commented Aug 9, 2022

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 abf3e9d9..793ffb3a 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..003e92ba5a
--- /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..298e9d5af8
--- /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..34bad2fd3c
--- /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..b14b9854a7
--- /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 e3704b567a..7de02531e7 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 5a0e03dda6..a1e95eade9 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 935d320353..d1ce6d7c4c 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-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 003e92ba5a..70ba454c96 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 298e9d5af8..1bdbecfad3 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 34bad2fd3c..dd7092eac3 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 b14b9854a7..dc748a61ad 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 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
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
Contributor Author

Choose a reason for hiding this comment

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

Totally agree.

@sandersn sandersn added this to Not started in PR Backlog Aug 17, 2022
@sandersn sandersn moved this from Not started to Waiting on reviewers in PR Backlog Aug 18, 2022
@andrewbranch
Copy link
Member

@typescript-bot perf test this
@typescript-bot pack this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Aug 19, 2022

Heya @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
Copy link
Collaborator

typescript-bot commented Aug 19, 2022

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

@andrewbranch
Copy link
Member

andrewbranch commented Aug 19, 2022

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 today
const [c, d = () => { console.log(c); return 0; }] = [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
Copy link
Collaborator

typescript-bot commented Aug 19, 2022

Hey @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
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
Collaborator

@andrewbranch
The results of the perf run you requested are in!

Here they are:

Compiler

Comparison Report - main..50241
Metric main 50241 Delta Best Worst
Angular - node (v10.16.3, x64)
Memory used 361,602k (± 0.02%) 361,626k (± 0.02%) +23k (+ 0.01%) 361,471k 361,865k
Parse Time 2.11s (± 0.63%) 2.10s (± 0.67%) -0.01s (- 0.47%) 2.08s 2.13s
Bind Time 0.90s (± 0.53%) 0.90s (± 0.58%) -0.00s (- 0.44%) 0.89s 0.91s
Check Time 6.10s (± 0.55%) 6.06s (± 0.39%) -0.04s (- 0.62%) 6.02s 6.11s
Emit Time 6.07s (± 0.88%) 6.00s (± 0.67%) -0.07s (- 1.22%) 5.91s 6.08s
Total Time 15.18s (± 0.48%) 15.05s (± 0.34%) -0.13s (- 0.84%) 14.96s 15.18s
Compiler-Unions - node (v10.16.3, x64)
Memory used 205,801k (± 0.03%) 205,724k (± 0.04%) -76k (- 0.04%) 205,518k 205,940k
Parse Time 0.83s (± 0.74%) 0.83s (± 0.96%) +0.00s (+ 0.12%) 0.81s 0.85s
Bind Time 0.53s (± 1.69%) 0.52s (± 1.11%) -0.00s (- 0.57%) 0.51s 0.54s
Check Time 7.39s (± 0.40%) 7.37s (± 0.85%) -0.02s (- 0.30%) 7.23s 7.55s
Emit Time 2.41s (± 0.85%) 2.42s (± 0.84%) +0.01s (+ 0.41%) 2.37s 2.47s
Total Time 11.17s (± 0.24%) 11.15s (± 0.56%) -0.02s (- 0.19%) 11.04s 11.31s
Monaco - node (v10.16.3, x64)
Memory used 344,139k (± 0.02%) 344,172k (± 0.02%) +34k (+ 0.01%) 344,054k 344,352k
Parse Time 1.60s (± 0.63%) 1.61s (± 0.41%) +0.01s (+ 0.31%) 1.60s 1.63s
Bind Time 0.76s (± 0.90%) 0.76s (± 1.16%) +0.00s (+ 0.53%) 0.74s 0.77s
Check Time 6.01s (± 0.47%) 5.99s (± 0.59%) -0.02s (- 0.32%) 5.89s 6.06s
Emit Time 3.24s (± 0.52%) 3.23s (± 0.56%) -0.01s (- 0.31%) 3.18s 3.25s
Total Time 11.61s (± 0.40%) 11.59s (± 0.42%) -0.02s (- 0.18%) 11.47s 11.68s
TFS - node (v10.16.3, x64)
Memory used 305,267k (± 0.02%) 305,268k (± 0.02%) +1k (+ 0.00%) 305,060k 305,389k
Parse Time 1.30s (± 0.76%) 1.29s (± 0.43%) -0.01s (- 0.46%) 1.28s 1.30s
Bind Time 0.72s (± 0.68%) 0.72s (± 0.77%) -0.00s (- 0.28%) 0.71s 0.73s
Check Time 5.47s (± 0.43%) 5.46s (± 0.23%) -0.01s (- 0.22%) 5.43s 5.49s
Emit Time 3.42s (± 0.58%) 3.38s (± 0.95%) -0.04s (- 1.14%) 3.31s 3.47s
Total Time 10.91s (± 0.33%) 10.85s (± 0.34%) -0.06s (- 0.54%) 10.77s 10.94s
material-ui - node (v10.16.3, x64)
Memory used 472,873k (± 0.01%) 472,882k (± 0.02%) +9k (+ 0.00%) 472,727k 473,032k
Parse Time 1.83s (± 0.83%) 1.85s (± 0.67%) +0.01s (+ 0.82%) 1.83s 1.89s
Bind Time 0.68s (± 1.00%) 0.68s (± 1.72%) -0.00s (- 0.44%) 0.66s 0.70s
Check Time 14.61s (± 0.91%) 14.67s (± 0.58%) +0.06s (+ 0.41%) 14.42s 14.83s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 17.12s (± 0.84%) 17.20s (± 0.56%) +0.07s (+ 0.43%) 16.92s 17.38s
xstate - node (v10.16.3, x64)
Memory used 582,739k (± 0.02%) 582,761k (± 0.01%) +22k (+ 0.00%) 582,639k 582,952k
Parse Time 2.61s (± 0.40%) 2.61s (± 0.45%) -0.00s (- 0.11%) 2.59s 2.64s
Bind Time 1.05s (± 0.97%) 1.04s (± 1.06%) -0.01s (- 0.86%) 1.02s 1.07s
Check Time 1.57s (± 0.82%) 1.57s (± 0.92%) -0.00s (- 0.13%) 1.54s 1.59s
Emit Time 0.07s (± 4.66%) 0.07s (± 3.14%) -0.00s (- 2.74%) 0.07s 0.08s
Total Time 5.30s (± 0.40%) 5.28s (± 0.53%) -0.02s (- 0.40%) 5.23s 5.36s
Angular - node (v12.1.0, x64)
Memory used 339,129k (± 0.02%) 339,136k (± 0.02%) +8k (+ 0.00%) 338,924k 339,293k
Parse Time 2.08s (± 0.61%) 2.10s (± 0.55%) +0.01s (+ 0.67%) 2.07s 2.12s
Bind Time 0.86s (± 1.10%) 0.86s (± 0.90%) +0.00s (+ 0.47%) 0.85s 0.88s
Check Time 5.85s (± 0.49%) 5.87s (± 0.50%) +0.01s (+ 0.17%) 5.81s 5.93s
Emit Time 6.24s (± 0.82%) 6.21s (± 0.63%) -0.03s (- 0.43%) 6.12s 6.34s
Total Time 15.03s (± 0.47%) 15.03s (± 0.39%) +0.00s (+ 0.01%) 14.88s 15.16s
Compiler-Unions - node (v12.1.0, x64)
Memory used 193,494k (± 0.04%) 193,400k (± 0.14%) -95k (- 0.05%) 192,351k 193,705k
Parse Time 0.82s (± 0.83%) 0.83s (± 0.70%) +0.00s (+ 0.36%) 0.81s 0.84s
Bind Time 0.55s (± 1.08%) 0.56s (± 0.85%) +0.00s (+ 0.36%) 0.55s 0.57s
Check Time 6.95s (± 0.52%) 6.94s (± 0.51%) -0.01s (- 0.13%) 6.85s 7.02s
Emit Time 2.46s (± 1.10%) 2.49s (± 1.38%) +0.04s (+ 1.51%) 2.43s 2.59s
Total Time 10.78s (± 0.49%) 10.81s (± 0.57%) +0.03s (+ 0.32%) 10.67s 11.00s
Monaco - node (v12.1.0, x64)
Memory used 327,074k (± 0.02%) 327,128k (± 0.01%) +54k (+ 0.02%) 327,026k 327,193k
Parse Time 1.58s (± 0.83%) 1.58s (± 0.71%) 0.00s ( 0.00%) 1.56s 1.61s
Bind Time 0.74s (± 1.14%) 0.75s (± 0.91%) +0.01s (+ 0.67%) 0.74s 0.77s
Check Time 5.82s (± 0.36%) 5.84s (± 0.43%) +0.02s (+ 0.40%) 5.80s 5.92s
Emit Time 3.27s (± 0.73%) 3.29s (± 0.89%) +0.02s (+ 0.49%) 3.25s 3.38s
Total Time 11.42s (± 0.34%) 11.46s (± 0.45%) +0.04s (+ 0.35%) 11.40s 11.60s
TFS - node (v12.1.0, x64)
Memory used 289,891k (± 0.02%) 289,829k (± 0.05%) -61k (- 0.02%) 289,305k 290,028k
Parse Time 1.30s (± 0.78%) 1.30s (± 0.54%) 0.00s ( 0.00%) 1.29s 1.32s
Bind Time 0.72s (± 1.17%) 0.72s (± 0.65%) -0.00s (- 0.14%) 0.71s 0.73s
Check Time 5.38s (± 0.32%) 5.40s (± 0.70%) +0.02s (+ 0.39%) 5.33s 5.50s
Emit Time 3.47s (± 1.13%) 3.52s (± 1.80%) +0.05s (+ 1.44%) 3.39s 3.73s
Total Time 10.87s (± 0.45%) 10.94s (± 0.90%) +0.07s (+ 0.62%) 10.77s 11.26s
material-ui - node (v12.1.0, x64)
Memory used 452,020k (± 0.01%) 452,063k (± 0.01%) +44k (+ 0.01%) 451,890k 452,187k
Parse Time 1.84s (± 1.43%) 1.84s (± 0.63%) -0.00s (- 0.16%) 1.82s 1.87s
Bind Time 0.67s (± 2.10%) 0.68s (± 1.45%) +0.00s (+ 0.59%) 0.66s 0.70s
Check Time 13.22s (± 0.47%) 13.17s (± 0.62%) -0.05s (- 0.39%) 12.97s 13.35s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 15.73s (± 0.53%) 15.68s (± 0.55%) -0.05s (- 0.30%) 15.48s 15.91s
xstate - node (v12.1.0, x64)
Memory used 554,320k (± 1.74%) 547,834k (± 0.01%) -6,486k (- 1.17%) 547,726k 547,951k
Parse Time 2.54s (± 0.61%) 2.54s (± 0.58%) +0.01s (+ 0.20%) 2.51s 2.59s
Bind Time 1.03s (± 1.21%) 1.03s (± 0.90%) -0.00s (- 0.19%) 1.01s 1.05s
Check Time 1.51s (± 0.38%) 1.51s (± 0.59%) +0.00s (+ 0.07%) 1.49s 1.53s
Emit Time 0.07s (± 0.00%) 0.07s (± 0.00%) 0.00s ( 0.00%) 0.07s 0.07s
Total Time 5.15s (± 0.48%) 5.16s (± 0.35%) +0.01s (+ 0.14%) 5.10s 5.19s
Angular - node (v14.15.1, x64)
Memory used 337,152k (± 0.01%) 337,160k (± 0.01%) +8k (+ 0.00%) 337,103k 337,208k
Parse Time 2.07s (± 0.42%) 2.07s (± 0.60%) -0.00s (- 0.24%) 2.04s 2.10s
Bind Time 0.90s (± 0.86%) 0.90s (± 0.53%) -0.00s (- 0.44%) 0.89s 0.91s
Check Time 5.88s (± 0.48%) 5.85s (± 0.41%) -0.02s (- 0.41%) 5.79s 5.90s
Emit Time 6.21s (± 0.50%) 6.23s (± 1.01%) +0.02s (+ 0.37%) 6.10s 6.37s
Total Time 15.06s (± 0.22%) 15.04s (± 0.45%) -0.01s (- 0.08%) 14.90s 15.24s
Compiler-Unions - node (v14.15.1, x64)
Memory used 192,021k (± 0.02%) 192,026k (± 0.02%) +5k (+ 0.00%) 191,939k 192,101k
Parse Time 0.85s (± 0.87%) 0.85s (± 0.56%) -0.00s (- 0.00%) 0.84s 0.86s
Bind Time 0.58s (± 0.69%) 0.58s (± 0.69%) -0.00s (- 0.00%) 0.57s 0.59s
Check Time 6.93s (± 0.42%) 6.95s (± 0.55%) +0.01s (+ 0.22%) 6.84s 7.01s
Emit Time 2.41s (± 0.70%) 2.43s (± 0.81%) +0.02s (+ 0.87%) 2.40s 2.48s
Total Time 10.78s (± 0.34%) 10.81s (± 0.46%) +0.03s (+ 0.30%) 10.67s 10.89s
Monaco - node (v14.15.1, x64)
Memory used 325,915k (± 0.00%) 325,904k (± 0.01%) -11k (- 0.00%) 325,871k 325,951k
Parse Time 1.58s (± 1.01%) 1.57s (± 0.58%) -0.01s (- 0.44%) 1.56s 1.59s
Bind Time 0.78s (± 0.96%) 0.77s (± 0.64%) -0.00s (- 0.39%) 0.77s 0.79s
Check Time 5.71s (± 0.63%) 5.69s (± 0.64%) -0.03s (- 0.44%) 5.62s 5.78s
Emit Time 3.34s (± 0.92%) 3.34s (± 0.61%) -0.00s (- 0.06%) 3.29s 3.37s
Total Time 11.40s (± 0.50%) 11.37s (± 0.49%) -0.03s (- 0.29%) 11.26s 11.50s
TFS - node (v14.15.1, x64)
Memory used 288,957k (± 0.01%) 288,977k (± 0.01%) +20k (+ 0.01%) 288,940k 289,023k
Parse Time 1.33s (± 1.79%) 1.33s (± 1.41%) +0.00s (+ 0.23%) 1.29s 1.37s
Bind Time 0.77s (± 4.71%) 0.77s (± 4.57%) -0.00s (- 0.13%) 0.73s 0.86s
Check Time 5.38s (± 0.64%) 5.38s (± 0.40%) -0.00s (- 0.02%) 5.34s 5.42s
Emit Time 3.60s (± 0.80%) 3.57s (± 1.86%) -0.04s (- 1.05%) 3.43s 3.66s
Total Time 11.09s (± 0.49%) 11.05s (± 0.60%) -0.04s (- 0.33%) 10.88s 11.18s
material-ui - node (v14.15.1, x64)
Memory used 450,317k (± 0.01%) 450,317k (± 0.00%) 0k ( 0.00%) 450,283k 450,367k
Parse Time 1.88s (± 0.31%) 1.89s (± 0.40%) +0.01s (+ 0.53%) 1.87s 1.90s
Bind Time 0.71s (± 0.83%) 0.72s (± 0.97%) +0.01s (+ 0.70%) 0.71s 0.73s
Check Time 13.23s (± 0.63%) 13.24s (± 0.77%) +0.01s (+ 0.10%) 13.07s 13.45s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 15.83s (± 0.52%) 15.85s (± 0.68%) +0.03s (+ 0.18%) 15.68s 16.06s
xstate - node (v14.15.1, x64)
Memory used 545,608k (± 0.00%) 545,649k (± 0.00%) +41k (+ 0.01%) 545,595k 545,707k
Parse Time 2.61s (± 0.48%) 2.60s (± 0.42%) -0.01s (- 0.31%) 2.58s 2.64s
Bind Time 1.16s (± 1.23%) 1.16s (± 0.66%) 0.00s ( 0.00%) 1.14s 1.17s
Check Time 1.56s (± 0.43%) 1.56s (± 0.53%) +0.01s (+ 0.45%) 1.55s 1.58s
Emit Time 0.07s (± 4.66%) 0.07s (± 4.92%) +0.00s (+ 1.37%) 0.07s 0.08s
Total Time 5.39s (± 0.39%) 5.39s (± 0.24%) +0.00s (+ 0.09%) 5.36s 5.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)
Benchmark Name Iterations
Current 50241 10
Baseline main 10

TSServer

Comparison Report - main..50241
Metric main 50241 Delta Best Worst
Compiler-UnionsTSServer - node (v10.16.3, x64)
Req 1 - updateOpen 1,464ms (± 0.42%) 1,458ms (± 0.62%) -6ms (- 0.42%) 1,439ms 1,481ms
Req 2 - geterr 3,810ms (± 0.43%) 3,787ms (± 0.55%) -23ms (- 0.60%) 3,738ms 3,822ms
Req 3 - references 279ms (± 0.81%) 278ms (± 0.97%) -1ms (- 0.32%) 274ms 287ms
Req 4 - navto 230ms (± 2.28%) 233ms (± 0.85%) +3ms (+ 1.22%) 229ms 238ms
Req 5 - completionInfo count 1,355 (± 0.00%) 1,355 (± 0.00%) 0 ( 0.00%) 1,355 1,355
Req 5 - completionInfo 64ms (± 4.32%) 65ms (± 4.23%) +2ms (+ 2.35%) 59ms 72ms
CompilerTSServer - node (v10.16.3, x64)
Req 1 - updateOpen 1,568ms (± 0.64%) 1,566ms (± 0.48%) -1ms (- 0.08%) 1,554ms 1,586ms
Req 2 - geterr 2,278ms (± 0.71%) 2,288ms (± 1.17%) +10ms (+ 0.44%) 2,249ms 2,389ms
Req 3 - references 298ms (± 1.59%) 303ms (± 2.55%) +5ms (+ 1.54%) 295ms 331ms
Req 4 - navto 234ms (± 2.52%) 236ms (± 2.16%) +2ms (+ 0.64%) 226ms 244ms
Req 5 - completionInfo count 1,517 (± 0.00%) 1,517 (± 0.00%) 0 ( 0.00%) 1,517 1,517
Req 5 - completionInfo 69ms (± 1.72%) 70ms (± 1.11%) +1ms (+ 1.01%) 68ms 72ms
xstateTSServer - node (v10.16.3, x64)
Req 1 - updateOpen 2,177ms (± 0.64%) 2,196ms (± 0.43%) +19ms (+ 0.87%) 2,179ms 2,226ms
Req 2 - geterr 777ms (± 0.51%) 778ms (± 0.45%) +1ms (+ 0.12%) 771ms 787ms
Req 3 - references 102ms (± 1.70%) 100ms (± 1.35%) -2ms (- 1.48%) 97ms 104ms
Req 4 - navto 251ms (± 1.49%) 253ms (± 0.78%) +2ms (+ 0.96%) 248ms 257ms
Req 5 - completionInfo count 3,293 (± 0.00%) 3,293 (± 0.00%) 0 ( 0.00%) 3,293 3,293
Req 5 - completionInfo 272ms (± 1.07%) 270ms (± 1.27%) -2ms (- 0.70%) 265ms 281ms
Compiler-UnionsTSServer - node (v12.1.0, x64)
Req 1 - updateOpen 1,498ms (± 0.67%) 1,484ms (± 0.61%) -14ms (- 0.93%) 1,467ms 1,506ms
Req 2 - geterr 3,559ms (± 0.69%) 3,562ms (± 0.76%) +3ms (+ 0.09%) 3,502ms 3,624ms
Req 3 - references 263ms (± 0.74%) 264ms (± 1.07%) +1ms (+ 0.49%) 259ms 272ms
Req 4 - navto 207ms (± 1.24%) 206ms (± 1.38%) -1ms (- 0.29%) 202ms 214ms
Req 5 - completionInfo count 1,355 (± 0.00%) 1,355 (± 0.00%) 0 ( 0.00%) 1,355 1,355
Req 5 - completionInfo 78ms (±12.61%) 74ms (±17.39%) 🟩-4ms (- 4.50%) 55ms 99ms
CompilerTSServer - node (v12.1.0, x64)
Req 1 - updateOpen 1,569ms (± 0.66%) 1,573ms (± 0.95%) +5ms (+ 0.29%) 1,542ms 1,624ms
Req 2 - geterr 2,222ms (± 0.40%) 2,221ms (± 0.54%) -1ms (- 0.04%) 2,191ms 2,254ms
Req 3 - references 275ms (± 0.42%) 274ms (± 0.75%) -1ms (- 0.18%) 269ms 277ms
Req 4 - navto 215ms (± 1.11%) 215ms (± 0.97%) -1ms (- 0.23%) 212ms 220ms
Req 5 - completionInfo count 1,517 (± 0.00%) 1,517 (± 0.00%) 0 ( 0.00%) 1,517 1,517
Req 5 - completionInfo 62ms (± 3.55%) 64ms (± 2.87%) +3ms (+ 4.39%) 60ms 67ms
xstateTSServer - node (v12.1.0, x64)
Req 1 - updateOpen 2,128ms (± 0.58%) 2,127ms (± 0.48%) -1ms (- 0.02%) 2,107ms 2,157ms
Req 2 - geterr 754ms (± 0.60%) 757ms (± 0.58%) +2ms (+ 0.32%) 749ms 770ms
Req 3 - references 68ms (± 1.32%) 68ms (± 1.20%) +0ms (+ 0.59%) 66ms 70ms
Req 4 - navto 240ms (± 1.26%) 239ms (± 1.91%) -1ms (- 0.46%) 229ms 251ms
Req 5 - completionInfo count 3,293 (± 0.00%) 3,293 (± 0.00%) 0 ( 0.00%) 3,293 3,293
Req 5 - completionInfo 267ms (± 0.73%) 268ms (± 0.61%) +1ms (+ 0.26%) 264ms 271ms
Compiler-UnionsTSServer - node (v14.15.1, x64)
Req 1 - updateOpen 1,543ms (± 0.27%) 1,538ms (± 0.65%) -5ms (- 0.32%) 1,519ms 1,568ms
Req 2 - geterr 3,687ms (± 0.72%) 3,685ms (± 0.61%) -1ms (- 0.04%) 3,638ms 3,753ms
Req 3 - references 278ms (± 0.75%) 278ms (± 0.88%) +0ms (+ 0.07%) 274ms 283ms
Req 4 - navto 220ms (± 0.75%) 219ms (± 0.65%) -1ms (- 0.59%) 217ms 222ms
Req 5 - completionInfo count 1,355 (± 0.00%) 1,355 (± 0.00%) 0 ( 0.00%) 1,355 1,355
Req 5 - completionInfo 58ms (± 5.58%) 55ms (± 1.65%) 🟩-3ms (- 4.52%) 53ms 57ms
CompilerTSServer - node (v14.15.1, x64)
Req 1 - updateOpen 1,608ms (± 0.69%) 1,606ms (± 0.32%) -2ms (- 0.12%) 1,591ms 1,615ms
Req 2 - geterr 2,344ms (± 0.45%) 2,348ms (± 0.61%) +4ms (+ 0.18%) 2,319ms 2,377ms
Req 3 - references 287ms (± 1.15%) 290ms (± 1.65%) +3ms (+ 1.01%) 283ms 298ms
Req 4 - navto 235ms (± 2.22%) 232ms (± 2.63%) -2ms (- 0.90%) 225ms 249ms
Req 5 - completionInfo count 1,517 (± 0.00%) 1,517 (± 0.00%) 0 ( 0.00%) 1,517 1,517
Req 5 - completionInfo 53ms (± 1.25%) 53ms (± 1.40%) -0ms (- 0.56%) 52ms 55ms
xstateTSServer - node (v14.15.1, x64)
Req 1 - updateOpen 2,224ms (± 0.47%) 2,231ms (± 0.41%) +7ms (+ 0.29%) 2,211ms 2,249ms
Req 2 - geterr 778ms (± 0.38%) 783ms (± 0.37%) +5ms (+ 0.60%) 776ms 790ms
Req 3 - references 66ms (± 1.06%) 67ms (± 0.89%) +1ms (+ 0.76%) 65ms 68ms
Req 4 - navto 245ms (± 1.13%) 248ms (± 0.93%) +3ms (+ 1.26%) 244ms 255ms
Req 5 - completionInfo count 3,293 (± 0.00%) 3,293 (± 0.00%) 0 ( 0.00%) 3,293 3,293
Req 5 - completionInfo 271ms (± 0.74%) 274ms (± 0.46%) +2ms (+ 0.89%) 270ms 276ms
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)
Benchmark Name Iterations
Current 50241 10
Baseline main 10

Developer Information:

Download Benchmark

@babakks
Copy link
Contributor Author

babakks commented Aug 21, 2022

@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
Copy link
Contributor Author

babakks commented Aug 22, 2022

@andrewbranch Could defining a new CheckMode value be a good idea? 🤔

@andrewbranch
Copy link
Member

@babakks @weswigham speculated that probably only CheckMode.Normal should issue errors, so maybe you don’t even need a new one.

@Andarist
Copy link
Contributor

Andarist commented Aug 23, 2022

I gotta say - I love your extensive descriptions/notes here, @babakks ❤️

@babakks
Copy link
Contributor Author

babakks commented Sep 1, 2022

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Backlog Bug PRs that fix a backlog bug
Projects
PR Backlog
  
Waiting on reviewers
Development

Successfully merging this pull request may close these issues.

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