mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-03 18:38:40 -06:00
Fix stack overflow in binding element type resolution with circular references
Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
This commit is contained in:
parent
def00df7a2
commit
9c7eea55ef
@ -11689,8 +11689,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
parentType = getNonNullableType(parentType);
|
||||
}
|
||||
// Filter `undefined` from the type we check against if the parent has an initializer and that initializer is not possibly `undefined`
|
||||
else if (strictNullChecks && pattern.parent.initializer && !(hasTypeFacts(getTypeOfInitializer(pattern.parent.initializer), TypeFacts.EQUndefined))) {
|
||||
parentType = getTypeWithFacts(parentType, TypeFacts.NEUndefined);
|
||||
// Use a non-recursive type check to avoid stack overflow when the initializer references binding elements
|
||||
else if (strictNullChecks && pattern.parent.initializer) {
|
||||
const initializerType = getQuickTypeOfExpression(pattern.parent.initializer) || getNodeLinks(pattern.parent.initializer).resolvedType;
|
||||
if (initializerType && !(hasTypeFacts(initializerType, TypeFacts.EQUndefined))) {
|
||||
parentType = getTypeWithFacts(parentType, TypeFacts.NEUndefined);
|
||||
}
|
||||
}
|
||||
|
||||
const accessFlags = AccessFlags.ExpressionPosition | (noTupleBoundsCheck || hasDefaultValue(declaration) ? AccessFlags.AllowMissing : 0);
|
||||
|
||||
@ -0,0 +1,80 @@
|
||||
circularBindingElementTypeResolution.ts(2,7): error TS2322: Type '{ c: number; f: any; }' is not assignable to type 'string | number'.
|
||||
circularBindingElementTypeResolution.ts(2,9): error TS2339: Property 'c' does not exist on type 'string | number'.
|
||||
circularBindingElementTypeResolution.ts(2,12): error TS2339: Property 'f' does not exist on type 'string | number'.
|
||||
circularBindingElementTypeResolution.ts(2,43): error TS2448: Block-scoped variable 'f' used before its declaration.
|
||||
circularBindingElementTypeResolution.ts(5,7): error TS2322: Type '{ a: number; f2: any; }' is not assignable to type 'string | number'.
|
||||
circularBindingElementTypeResolution.ts(5,9): error TS2339: Property 'a' does not exist on type 'string | number'.
|
||||
circularBindingElementTypeResolution.ts(5,12): error TS2339: Property 'f2' does not exist on type 'string | number'.
|
||||
circularBindingElementTypeResolution.ts(5,53): error TS2448: Block-scoped variable 'f2' used before its declaration.
|
||||
circularBindingElementTypeResolution.ts(8,7): error TS2322: Type '{ a2: any; f3: any; }' is not assignable to type 'string | number'.
|
||||
circularBindingElementTypeResolution.ts(8,9): error TS2339: Property 'a2' does not exist on type 'string | number'.
|
||||
circularBindingElementTypeResolution.ts(8,13): error TS2339: Property 'f3' does not exist on type 'string | number'.
|
||||
circularBindingElementTypeResolution.ts(8,43): error TS2448: Block-scoped variable 'f3' used before its declaration.
|
||||
circularBindingElementTypeResolution.ts(8,51): error TS2448: Block-scoped variable 'a2' used before its declaration.
|
||||
circularBindingElementTypeResolution.ts(11,80): error TS2322: Type 'string' is not assignable to type 'number'.
|
||||
circularBindingElementTypeResolution.ts(11,83): error TS2448: Block-scoped variable 'y' used before its declaration.
|
||||
circularBindingElementTypeResolution.ts(11,83): error TS2454: Variable 'y' is used before being assigned.
|
||||
circularBindingElementTypeResolution.ts(11,86): error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
circularBindingElementTypeResolution.ts(11,89): error TS2448: Block-scoped variable 'x' used before its declaration.
|
||||
circularBindingElementTypeResolution.ts(11,89): error TS2454: Variable 'x' is used before being assigned.
|
||||
|
||||
|
||||
==== circularBindingElementTypeResolution.ts (19 errors) ====
|
||||
// Test case 1: Simple self-reference with shorthand property
|
||||
const { c, f }: string | number = { c: 0, f };
|
||||
~~~~~~~~
|
||||
!!! error TS2322: Type '{ c: number; f: any; }' is not assignable to type 'string | number'.
|
||||
~
|
||||
!!! error TS2339: Property 'c' does not exist on type 'string | number'.
|
||||
~
|
||||
!!! error TS2339: Property 'f' does not exist on type 'string | number'.
|
||||
~
|
||||
!!! error TS2448: Block-scoped variable 'f' used before its declaration.
|
||||
!!! related TS2728 circularBindingElementTypeResolution.ts:2:12: 'f' is declared here.
|
||||
|
||||
// Test case 2: Self-reference with expression
|
||||
const { a, f2 }: string | number = { a: 0, f2: (1 + f2) };
|
||||
~~~~~~~~~
|
||||
!!! error TS2322: Type '{ a: number; f2: any; }' is not assignable to type 'string | number'.
|
||||
~
|
||||
!!! error TS2339: Property 'a' does not exist on type 'string | number'.
|
||||
~~
|
||||
!!! error TS2339: Property 'f2' does not exist on type 'string | number'.
|
||||
~~
|
||||
!!! error TS2448: Block-scoped variable 'f2' used before its declaration.
|
||||
!!! related TS2728 circularBindingElementTypeResolution.ts:5:12: 'f2' is declared here.
|
||||
|
||||
// Test case 3: Circular reference between two binding elements
|
||||
const { a2, f3 }: string | number = { a2: f3, f3: a2 };
|
||||
~~~~~~~~~~
|
||||
!!! error TS2322: Type '{ a2: any; f3: any; }' is not assignable to type 'string | number'.
|
||||
~~
|
||||
!!! error TS2339: Property 'a2' does not exist on type 'string | number'.
|
||||
~~
|
||||
!!! error TS2339: Property 'f3' does not exist on type 'string | number'.
|
||||
~~
|
||||
!!! error TS2448: Block-scoped variable 'f3' used before its declaration.
|
||||
!!! related TS2728 circularBindingElementTypeResolution.ts:8:13: 'f3' is declared here.
|
||||
~~
|
||||
!!! error TS2448: Block-scoped variable 'a2' used before its declaration.
|
||||
!!! related TS2728 circularBindingElementTypeResolution.ts:8:9: 'a2' is declared here.
|
||||
|
||||
// Test case 4: Nested destructuring with self-reference
|
||||
const { nested: { x, y } }: { nested: { x: number, y: string } } = { nested: { x: y, y: x } };
|
||||
~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'number'.
|
||||
!!! related TS6500 circularBindingElementTypeResolution.ts:11:41: The expected type comes from property 'x' which is declared here on type '{ x: number; y: string; }'
|
||||
~
|
||||
!!! error TS2448: Block-scoped variable 'y' used before its declaration.
|
||||
!!! related TS2728 circularBindingElementTypeResolution.ts:11:22: 'y' is declared here.
|
||||
~
|
||||
!!! error TS2454: Variable 'y' is used before being assigned.
|
||||
~
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
!!! related TS6500 circularBindingElementTypeResolution.ts:11:52: The expected type comes from property 'y' which is declared here on type '{ x: number; y: string; }'
|
||||
~
|
||||
!!! error TS2448: Block-scoped variable 'x' used before its declaration.
|
||||
!!! related TS2728 circularBindingElementTypeResolution.ts:11:19: 'x' is declared here.
|
||||
~
|
||||
!!! error TS2454: Variable 'x' is used before being assigned.
|
||||
|
||||
@ -0,0 +1,41 @@
|
||||
//// [tests/cases/compiler/circularBindingElementTypeResolution.ts] ////
|
||||
|
||||
=== circularBindingElementTypeResolution.ts ===
|
||||
// Test case 1: Simple self-reference with shorthand property
|
||||
const { c, f }: string | number = { c: 0, f };
|
||||
>c : Symbol(c, Decl(circularBindingElementTypeResolution.ts, 1, 7))
|
||||
>f : Symbol(f, Decl(circularBindingElementTypeResolution.ts, 1, 10))
|
||||
>c : Symbol(c, Decl(circularBindingElementTypeResolution.ts, 1, 35))
|
||||
>f : Symbol(f, Decl(circularBindingElementTypeResolution.ts, 1, 41))
|
||||
|
||||
// Test case 2: Self-reference with expression
|
||||
const { a, f2 }: string | number = { a: 0, f2: (1 + f2) };
|
||||
>a : Symbol(a, Decl(circularBindingElementTypeResolution.ts, 4, 7))
|
||||
>f2 : Symbol(f2, Decl(circularBindingElementTypeResolution.ts, 4, 10))
|
||||
>a : Symbol(a, Decl(circularBindingElementTypeResolution.ts, 4, 36))
|
||||
>f2 : Symbol(f2, Decl(circularBindingElementTypeResolution.ts, 4, 42))
|
||||
>f2 : Symbol(f2, Decl(circularBindingElementTypeResolution.ts, 4, 10))
|
||||
|
||||
// Test case 3: Circular reference between two binding elements
|
||||
const { a2, f3 }: string | number = { a2: f3, f3: a2 };
|
||||
>a2 : Symbol(a2, Decl(circularBindingElementTypeResolution.ts, 7, 7))
|
||||
>f3 : Symbol(f3, Decl(circularBindingElementTypeResolution.ts, 7, 11))
|
||||
>a2 : Symbol(a2, Decl(circularBindingElementTypeResolution.ts, 7, 37))
|
||||
>f3 : Symbol(f3, Decl(circularBindingElementTypeResolution.ts, 7, 11))
|
||||
>f3 : Symbol(f3, Decl(circularBindingElementTypeResolution.ts, 7, 45))
|
||||
>a2 : Symbol(a2, Decl(circularBindingElementTypeResolution.ts, 7, 7))
|
||||
|
||||
// Test case 4: Nested destructuring with self-reference
|
||||
const { nested: { x, y } }: { nested: { x: number, y: string } } = { nested: { x: y, y: x } };
|
||||
>nested : Symbol(nested, Decl(circularBindingElementTypeResolution.ts, 10, 29))
|
||||
>x : Symbol(x, Decl(circularBindingElementTypeResolution.ts, 10, 17))
|
||||
>y : Symbol(y, Decl(circularBindingElementTypeResolution.ts, 10, 20))
|
||||
>nested : Symbol(nested, Decl(circularBindingElementTypeResolution.ts, 10, 29))
|
||||
>x : Symbol(x, Decl(circularBindingElementTypeResolution.ts, 10, 39))
|
||||
>y : Symbol(y, Decl(circularBindingElementTypeResolution.ts, 10, 50))
|
||||
>nested : Symbol(nested, Decl(circularBindingElementTypeResolution.ts, 10, 68))
|
||||
>x : Symbol(x, Decl(circularBindingElementTypeResolution.ts, 10, 78))
|
||||
>y : Symbol(y, Decl(circularBindingElementTypeResolution.ts, 10, 20))
|
||||
>y : Symbol(y, Decl(circularBindingElementTypeResolution.ts, 10, 84))
|
||||
>x : Symbol(x, Decl(circularBindingElementTypeResolution.ts, 10, 17))
|
||||
|
||||
@ -0,0 +1,87 @@
|
||||
//// [tests/cases/compiler/circularBindingElementTypeResolution.ts] ////
|
||||
|
||||
=== circularBindingElementTypeResolution.ts ===
|
||||
// Test case 1: Simple self-reference with shorthand property
|
||||
const { c, f }: string | number = { c: 0, f };
|
||||
>c : any
|
||||
> : ^^^
|
||||
>f : any
|
||||
> : ^^^
|
||||
>{ c: 0, f } : { c: number; f: any; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^
|
||||
>c : number
|
||||
> : ^^^^^^
|
||||
>0 : 0
|
||||
> : ^
|
||||
>f : any
|
||||
> : ^^^
|
||||
|
||||
// Test case 2: Self-reference with expression
|
||||
const { a, f2 }: string | number = { a: 0, f2: (1 + f2) };
|
||||
>a : any
|
||||
> : ^^^
|
||||
>f2 : any
|
||||
> : ^^^
|
||||
>{ a: 0, f2: (1 + f2) } : { a: number; f2: any; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>a : number
|
||||
> : ^^^^^^
|
||||
>0 : 0
|
||||
> : ^
|
||||
>f2 : any
|
||||
> : ^^^
|
||||
>(1 + f2) : any
|
||||
> : ^^^
|
||||
>1 + f2 : any
|
||||
> : ^^^
|
||||
>1 : 1
|
||||
> : ^
|
||||
>f2 : any
|
||||
> : ^^^
|
||||
|
||||
// Test case 3: Circular reference between two binding elements
|
||||
const { a2, f3 }: string | number = { a2: f3, f3: a2 };
|
||||
>a2 : any
|
||||
> : ^^^
|
||||
>f3 : any
|
||||
> : ^^^
|
||||
>{ a2: f3, f3: a2 } : { a2: any; f3: any; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^
|
||||
>a2 : any
|
||||
> : ^^^
|
||||
>f3 : any
|
||||
> : ^^^
|
||||
>f3 : any
|
||||
> : ^^^
|
||||
>a2 : any
|
||||
> : ^^^
|
||||
|
||||
// Test case 4: Nested destructuring with self-reference
|
||||
const { nested: { x, y } }: { nested: { x: number, y: string } } = { nested: { x: y, y: x } };
|
||||
>nested : any
|
||||
> : ^^^
|
||||
>x : number
|
||||
> : ^^^^^^
|
||||
>y : string
|
||||
> : ^^^^^^
|
||||
>nested : { x: number; y: string; }
|
||||
> : ^^^^^ ^^^^^ ^^^
|
||||
>x : number
|
||||
> : ^^^^^^
|
||||
>y : string
|
||||
> : ^^^^^^
|
||||
>{ nested: { x: y, y: x } } : { nested: { x: string; y: number; }; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>nested : { x: string; y: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>{ x: y, y: x } : { x: string; y: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>x : string
|
||||
> : ^^^^^^
|
||||
>y : string
|
||||
> : ^^^^^^
|
||||
>y : number
|
||||
> : ^^^^^^
|
||||
>x : number
|
||||
> : ^^^^^^
|
||||
|
||||
14
tests/cases/compiler/circularBindingElementTypeResolution.ts
Normal file
14
tests/cases/compiler/circularBindingElementTypeResolution.ts
Normal file
@ -0,0 +1,14 @@
|
||||
// @strict: true
|
||||
// @noEmit: true
|
||||
|
||||
// Test case 1: Simple self-reference with shorthand property
|
||||
const { c, f }: string | number = { c: 0, f };
|
||||
|
||||
// Test case 2: Self-reference with expression
|
||||
const { a, f2 }: string | number = { a: 0, f2: (1 + f2) };
|
||||
|
||||
// Test case 3: Circular reference between two binding elements
|
||||
const { a2, f3 }: string | number = { a2: f3, f3: a2 };
|
||||
|
||||
// Test case 4: Nested destructuring with self-reference
|
||||
const { nested: { x, y } }: { nested: { x: number, y: string } } = { nested: { x: y, y: x } };
|
||||
Loading…
x
Reference in New Issue
Block a user