Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28312,7 +28312,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// from its initializer, we'll already have cached the type. Otherwise we compute it now
// without caching such that transient types are reflected.
const links = getNodeLinks(node);
return links.resolvedType || getTypeOfExpression(node);
if (links.resolvedType) {
return links.resolvedType;
}
const pattern = isVariableDeclaration(node.parent) && node.parent.initializer === node && isBindingPattern(node.parent.name)
? node.parent.name
: undefined;
if (pattern) {
contextualBindingPatterns.push(pattern);
const type = getTypeOfExpression(node);
contextualBindingPatterns.pop();
return type;
}
return getTypeOfExpression(node);
}

function getInitialTypeOfVariableDeclaration(node: VariableDeclaration) {
Expand Down Expand Up @@ -31023,7 +31035,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// If the identifier is declared in a binding pattern for which we're currently computing the implied type and the
// reference occurs with the same binding pattern, return the non-inferrable any type. This for example occurs in
// 'const [a, b = a + 1] = [2]' when we're computing the contextual type for the array literal '[2]'.
if (declaration && declaration.kind === SyntaxKind.BindingElement && contains(contextualBindingPatterns, declaration.parent) && findAncestor(node, parent => parent === declaration!.parent)) {
if (declaration && declaration.kind === SyntaxKind.BindingElement && contains(contextualBindingPatterns, declaration.parent)) {
return nonInferrableAnyType;
}

Expand Down Expand Up @@ -45047,7 +45059,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// Don't validate for-in initializer as it is already an error
const widenedType = getWidenedTypeForVariableLikeDeclaration(node);
if (needCheckInitializer) {
contextualBindingPatterns.push(node.name);
const initializerType = checkExpressionCached(node.initializer);
contextualBindingPatterns.pop();
if (strictNullChecks && needCheckWidenedType) {
checkNonNullNonVoidType(initializerType, node);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
destructuringContextualBindingStackOverflow.ts(1,7): error TS2322: Type '{ c: number; f: any; }' is not assignable to type 'string | number | symbol'.
destructuringContextualBindingStackOverflow.ts(1,9): error TS2339: Property 'c' does not exist on type 'string | number | symbol'.
destructuringContextualBindingStackOverflow.ts(1,12): error TS2339: Property 'f' does not exist on type 'string | number | symbol'.
destructuringContextualBindingStackOverflow.ts(1,52): error TS2448: Block-scoped variable 'f' used before its declaration.
destructuringContextualBindingStackOverflow.ts(2,7): error TS2322: Type '{ a: number; f: any; }' is not assignable to type 'string | number'.
destructuringContextualBindingStackOverflow.ts(2,9): error TS2339: Property 'a' does not exist on type 'string | number'.
destructuringContextualBindingStackOverflow.ts(2,12): error TS2339: Property 'f' does not exist on type 'string | number'.
destructuringContextualBindingStackOverflow.ts(2,55): error TS2448: Block-scoped variable 'f1' used before its declaration.
destructuringContextualBindingStackOverflow.ts(3,7): error TS2322: Type '{ a: any; f: any; }' is not assignable to type 'string | number'.
destructuringContextualBindingStackOverflow.ts(3,9): error TS2339: Property 'a' does not exist on type 'string | number'.
destructuringContextualBindingStackOverflow.ts(3,16): error TS2339: Property 'f' does not exist on type 'string | number'.
destructuringContextualBindingStackOverflow.ts(3,48): error TS2448: Block-scoped variable 'f2' used before its declaration.
destructuringContextualBindingStackOverflow.ts(3,55): error TS2448: Block-scoped variable 'a1' used before its declaration.


==== destructuringContextualBindingStackOverflow.ts (13 errors) ====
const { c, f }: string | number | symbol = { c: 0, f };
~~~~~~~~
!!! error TS2322: Type '{ c: number; f: any; }' is not assignable to type 'string | number | symbol'.
~
!!! error TS2339: Property 'c' does not exist on type 'string | number | symbol'.
~
!!! error TS2339: Property 'f' does not exist on type 'string | number | symbol'.
~
!!! error TS2448: Block-scoped variable 'f' used before its declaration.
!!! related TS2728 destructuringContextualBindingStackOverflow.ts:1:12: 'f' is declared here.
const { a, f: f1 }: string | number = { a: 0, f: (1 + f1) };
~~~~~~~~~~~~
!!! error TS2322: Type '{ a: number; f: any; }' is not assignable to type 'string | number'.
~
!!! error TS2339: Property 'a' does not exist on type 'string | number'.
~
!!! error TS2339: Property 'f' does not exist on type 'string | number'.
~~
!!! error TS2448: Block-scoped variable 'f1' used before its declaration.
!!! related TS2728 destructuringContextualBindingStackOverflow.ts:2:15: 'f1' is declared here.
const { a: a1, f: f2 }: string | number = { a: f2, f: a1 };
~~~~~~~~~~~~~~~~
!!! error TS2322: Type '{ a: any; f: any; }' is not assignable to type 'string | number'.
~
!!! error TS2339: Property 'a' does not exist on type 'string | number'.
~
!!! error TS2339: Property 'f' does not exist on type 'string | number'.
~~
!!! error TS2448: Block-scoped variable 'f2' used before its declaration.
!!! related TS2728 destructuringContextualBindingStackOverflow.ts:3:19: 'f2' is declared here.
~~
!!! error TS2448: Block-scoped variable 'a1' used before its declaration.
!!! related TS2728 destructuringContextualBindingStackOverflow.ts:3:12: 'a1' is declared here.

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//// [tests/cases/compiler/destructuringContextualBindingStackOverflow.ts] ////

//// [destructuringContextualBindingStackOverflow.ts]
const { c, f }: string | number | symbol = { c: 0, f };
const { a, f: f1 }: string | number = { a: 0, f: (1 + f1) };
const { a: a1, f: f2 }: string | number = { a: f2, f: a1 };


//// [destructuringContextualBindingStackOverflow.js]
"use strict";
var _a = { c: 0, f: f }, c = _a.c, f = _a.f;
var _b = { a: 0, f: (1 + f1) }, a = _b.a, f1 = _b.f;
var _c = { a: f2, f: a1 }, a1 = _c.a, f2 = _c.f;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//// [tests/cases/compiler/destructuringContextualBindingStackOverflow.ts] ////

=== destructuringContextualBindingStackOverflow.ts ===
const { c, f }: string | number | symbol = { c: 0, f };
>c : Symbol(c, Decl(destructuringContextualBindingStackOverflow.ts, 0, 7))
>f : Symbol(f, Decl(destructuringContextualBindingStackOverflow.ts, 0, 10))
>c : Symbol(c, Decl(destructuringContextualBindingStackOverflow.ts, 0, 44))
>f : Symbol(f, Decl(destructuringContextualBindingStackOverflow.ts, 0, 50))

const { a, f: f1 }: string | number = { a: 0, f: (1 + f1) };
>a : Symbol(a, Decl(destructuringContextualBindingStackOverflow.ts, 1, 7))
>f1 : Symbol(f1, Decl(destructuringContextualBindingStackOverflow.ts, 1, 10))
>a : Symbol(a, Decl(destructuringContextualBindingStackOverflow.ts, 1, 39))
>f : Symbol(f, Decl(destructuringContextualBindingStackOverflow.ts, 1, 45))
>f1 : Symbol(f1, Decl(destructuringContextualBindingStackOverflow.ts, 1, 10))

const { a: a1, f: f2 }: string | number = { a: f2, f: a1 };
>a1 : Symbol(a1, Decl(destructuringContextualBindingStackOverflow.ts, 2, 7))
>f2 : Symbol(f2, Decl(destructuringContextualBindingStackOverflow.ts, 2, 14))
>a : Symbol(a, Decl(destructuringContextualBindingStackOverflow.ts, 2, 43))
>f2 : Symbol(f2, Decl(destructuringContextualBindingStackOverflow.ts, 2, 14))
>f : Symbol(f, Decl(destructuringContextualBindingStackOverflow.ts, 2, 50))
>a1 : Symbol(a1, Decl(destructuringContextualBindingStackOverflow.ts, 2, 7))

Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//// [tests/cases/compiler/destructuringContextualBindingStackOverflow.ts] ////

=== destructuringContextualBindingStackOverflow.ts ===
const { c, f }: string | number | symbol = { c: 0, f };
>c : any
> : ^^^
>f : any
> : ^^^
>{ c: 0, f } : { c: number; f: any; }
> : ^^^^^^^^^^^^^^^^^^^^^^
>c : number
> : ^^^^^^
>0 : 0
> : ^
>f : any
> : ^^^

const { a, f: f1 }: string | number = { a: 0, f: (1 + f1) };
>a : any
> : ^^^
>f : any
> : ^^^
>f1 : any
> : ^^^
>{ a: 0, f: (1 + f1) } : { a: number; f: any; }
> : ^^^^^^^^^^^^^^^^^^^^^^
>a : number
> : ^^^^^^
>0 : 0
> : ^
>f : any
> : ^^^
>(1 + f1) : any
> : ^^^
>1 + f1 : any
> : ^^^
>1 : 1
> : ^
>f1 : any
> : ^^^

const { a: a1, f: f2 }: string | number = { a: f2, f: a1 };
>a : any
> : ^^^
>a1 : any
> : ^^^
>f : any
> : ^^^
>f2 : any
> : ^^^
>{ a: f2, f: a1 } : { a: any; f: any; }
> : ^^^^^^^^^^^^^^^^^^^
>a : any
> : ^^^
>f2 : any
> : ^^^
>f : any
> : ^^^
>a1 : any
> : ^^^

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// @strict: true

const { c, f }: string | number | symbol = { c: 0, f };
const { a, f: f1 }: string | number = { a: 0, f: (1 + f1) };
const { a: a1, f: f2 }: string | number = { a: f2, f: a1 };