Skip to content
Open
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
29 changes: 12 additions & 17 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30853,7 +30853,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
function getNarrowedTypeOfSymbol(symbol: Symbol, location: Identifier) {
const type = getTypeOfSymbol(symbol);
const declaration = symbol.valueDeclaration;
if (declaration) {
if (declaration && !textRangeContainsPositionInclusive(getRootDeclaration(declaration), location.pos)) {
// If we have a non-rest binding element with no initializer declared as a const variable or a const-like
// parameter (a parameter for which there are no assignments in the function body), and if the parent type
// for the destructuring is a union type, one or more of the binding elements may represent discriminant
Expand Down Expand Up @@ -30881,23 +30881,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const parent = declaration.parent.parent;
const rootDeclaration = getRootDeclaration(parent);
if (rootDeclaration.kind === SyntaxKind.VariableDeclaration && getCombinedNodeFlagsCached(rootDeclaration) & NodeFlags.Constant || rootDeclaration.kind === SyntaxKind.Parameter) {
const links = getNodeLinks(parent);
if (!(links.flags & NodeCheckFlags.InCheckIdentifier)) {
links.flags |= NodeCheckFlags.InCheckIdentifier;
const parentType = getTypeForBindingElementParent(parent, CheckMode.Normal);
const parentTypeConstraint = parentType && mapType(parentType, getBaseConstraintOrType);
links.flags &= ~NodeCheckFlags.InCheckIdentifier;
if (parentTypeConstraint && parentTypeConstraint.flags & TypeFlags.Union && !(rootDeclaration.kind === SyntaxKind.Parameter && isSomeSymbolAssigned(rootDeclaration))) {
const pattern = declaration.parent;
const narrowedType = getFlowTypeOfReference(pattern, parentTypeConstraint, parentTypeConstraint, /*flowContainer*/ undefined, location.flowNode);
if (narrowedType.flags & TypeFlags.Never) {
return neverType;
}
// Destructurings are validated against the parent type elsewhere. Here we disable tuple bounds
// checks because the narrowed type may have lower arity than the full parent type. For example,
// for the declaration [x, y]: [1, 2] | [3], we may have narrowed the parent type to just [3].
return getBindingElementTypeFromParentType(declaration, narrowedType, /*noTupleBoundsCheck*/ true);
const parentType = getTypeForBindingElementParent(parent, CheckMode.Normal);
const parentTypeConstraint = parentType && mapType(parentType, getBaseConstraintOrType);
if (parentTypeConstraint && parentTypeConstraint.flags & TypeFlags.Union && !(rootDeclaration.kind === SyntaxKind.Parameter && isSomeSymbolAssigned(rootDeclaration))) {
const pattern = declaration.parent;
const narrowedType = getFlowTypeOfReference(pattern, parentTypeConstraint, parentTypeConstraint, /*flowContainer*/ undefined, location.flowNode);
if (narrowedType.flags & TypeFlags.Never) {
return neverType;
}
// Destructurings are validated against the parent type elsewhere. Here we disable tuple bounds
// checks because the narrowed type may have lower arity than the full parent type. For example,
// for the declaration [x, y]: [1, 2] | [3], we may have narrowed the parent type to just [3].
return getBindingElementTypeFromParentType(declaration, narrowedType, /*noTupleBoundsCheck*/ true);
}
}
}
Expand Down
3 changes: 1 addition & 2 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6240,8 +6240,7 @@ export const enum NodeCheckFlags {
ConstructorReference = 1 << 29, // Binding to a class constructor inside of the class's body.
ContainsClassWithPrivateIdentifiers = 1 << 20, // Marked on all block-scoped containers containing a class with private identifiers.
ContainsSuperPropertyInStaticInitializer = 1 << 21, // Marked on all block-scoped containers containing a static initializer with 'super.x' or 'super[x]'.
InCheckIdentifier = 1 << 22,
PartiallyTypeChecked = 1 << 23, // Node has been partially type checked
PartiallyTypeChecked = 1 << 22, // Node has been partially type checked

/** These flags are LazyNodeCheckFlags and can be calculated lazily by `hasNodeCheckFlag` */
LazyFlags = SuperInstance
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
dependentDestructuredVariablesNoCrash1.ts(3,10): error TS7010: 'f', which lacks return-type annotation, implicitly has an 'any' return type.
dependentDestructuredVariablesNoCrash1.ts(5,12): error TS1015: Parameter cannot have question mark and initializer.
dependentDestructuredVariablesNoCrash1.ts(5,12): error TS2488: Type '(() => any) | undefined' must have a '[Symbol.iterator]()' method that returns an iterator.
dependentDestructuredVariablesNoCrash1.ts(5,20): error TS7022: 'undefined' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
dependentDestructuredVariablesNoCrash1.ts(5,45): error TS2373: Parameter '[first, undefined]' cannot reference identifier 'undefined' declared after it.


==== dependentDestructuredVariablesNoCrash1.ts (5 errors) ====
// https://github.com/microsoft/TypeScript/issues/63044

function f()
~
!!! error TS7010: 'f', which lacks return-type annotation, implicitly has an 'any' return type.

function f([first, undefined]?: () => any = undefined) {}
~~~~~~~~~~~~~~~~~~
!!! error TS1015: Parameter cannot have question mark and initializer.
~~~~~~~~~~~~~~~~~~
!!! error TS2488: Type '(() => any) | undefined' must have a '[Symbol.iterator]()' method that returns an iterator.
~~~~~~~~~
!!! error TS7022: 'undefined' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
~~~~~~~~~
!!! error TS2373: Parameter '[first, undefined]' cannot reference identifier 'undefined' declared after it.

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//// [tests/cases/conformance/controlFlow/dependentDestructuredVariablesNoCrash1.ts] ////

//// [dependentDestructuredVariablesNoCrash1.ts]
// https://github.com/microsoft/TypeScript/issues/63044

function f()

function f([first, undefined]?: () => any = undefined) {}


//// [dependentDestructuredVariablesNoCrash1.js]
"use strict";
// https://github.com/microsoft/TypeScript/issues/63044
function f([first, undefined] = undefined) { }


//// [dependentDestructuredVariablesNoCrash1.d.ts]
declare function f(): any;
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//// [tests/cases/conformance/controlFlow/dependentDestructuredVariablesNoCrash1.ts] ////

=== dependentDestructuredVariablesNoCrash1.ts ===
// https://github.com/microsoft/TypeScript/issues/63044

function f()
>f : Symbol(f, Decl(dependentDestructuredVariablesNoCrash1.ts, 0, 0), Decl(dependentDestructuredVariablesNoCrash1.ts, 2, 12))

function f([first, undefined]?: () => any = undefined) {}
>f : Symbol(f, Decl(dependentDestructuredVariablesNoCrash1.ts, 0, 0), Decl(dependentDestructuredVariablesNoCrash1.ts, 2, 12))
>first : Symbol(first, Decl(dependentDestructuredVariablesNoCrash1.ts, 4, 12))
>undefined : Symbol(undefined, Decl(dependentDestructuredVariablesNoCrash1.ts, 4, 18))
>undefined : Symbol(undefined, Decl(dependentDestructuredVariablesNoCrash1.ts, 4, 18))

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//// [tests/cases/conformance/controlFlow/dependentDestructuredVariablesNoCrash1.ts] ////

=== dependentDestructuredVariablesNoCrash1.ts ===
// https://github.com/microsoft/TypeScript/issues/63044

function f()
>f : () => any
> : ^^^^^^^^^

function f([first, undefined]?: () => any = undefined) {}
>f : () => any
> : ^^^^^^^^^
>first : any
> : ^^^
>undefined : any
> : ^^^
>undefined : any
> : ^^^

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
dependentDestructuredVariablesNoCrash2.ts(3,9): error TS7010: '(Missing)', which lacks return-type annotation, implicitly has an 'any' return type.
dependentDestructuredVariablesNoCrash2.ts(3,10): error TS1003: Identifier expected.
dependentDestructuredVariablesNoCrash2.ts(3,11): error TS2488: Type 'string | undefined' must have a '[Symbol.iterator]()' method that returns an iterator.
dependentDestructuredVariablesNoCrash2.ts(3,11): error TS2371: A parameter initializer is only allowed in a function or constructor implementation.
dependentDestructuredVariablesNoCrash2.ts(3,12): error TS7022: 'undefined' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
dependentDestructuredVariablesNoCrash2.ts(3,54): error TS2373: Parameter '[undefined, unknown]' cannot reference identifier 'undefined' declared after it.


==== dependentDestructuredVariablesNoCrash2.ts (6 errors) ====
// https://github.com/microsoft/TypeScript/issues/63091

function ([undefined, unknown]: string | undefined = undefined)

!!! error TS7010: '(Missing)', which lacks return-type annotation, implicitly has an 'any' return type.
~
!!! error TS1003: Identifier expected.
~~~~~~~~~~~~~~~~~~~~
!!! error TS2488: Type 'string | undefined' must have a '[Symbol.iterator]()' method that returns an iterator.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2371: A parameter initializer is only allowed in a function or constructor implementation.
~~~~~~~~~
!!! error TS7022: 'undefined' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
~~~~~~~~~
!!! error TS2373: Parameter '[undefined, unknown]' cannot reference identifier 'undefined' declared after it.

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//// [tests/cases/conformance/controlFlow/dependentDestructuredVariablesNoCrash2.ts] ////

//// [dependentDestructuredVariablesNoCrash2.ts]
// https://github.com/microsoft/TypeScript/issues/63091

function ([undefined, unknown]: string | undefined = undefined)


//// [dependentDestructuredVariablesNoCrash2.js]
"use strict";
// https://github.com/microsoft/TypeScript/issues/63091


//// [dependentDestructuredVariablesNoCrash2.d.ts]
declare function ([undefined, unknown]?: string | undefined): any;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//// [tests/cases/conformance/controlFlow/dependentDestructuredVariablesNoCrash2.ts] ////

=== dependentDestructuredVariablesNoCrash2.ts ===
// https://github.com/microsoft/TypeScript/issues/63091

function ([undefined, unknown]: string | undefined = undefined)
> : Symbol((Missing), Decl(dependentDestructuredVariablesNoCrash2.ts, 0, 0))
>undefined : Symbol(undefined, Decl(dependentDestructuredVariablesNoCrash2.ts, 2, 11))
>unknown : Symbol(unknown, Decl(dependentDestructuredVariablesNoCrash2.ts, 2, 21))
>undefined : Symbol(undefined, Decl(dependentDestructuredVariablesNoCrash2.ts, 2, 11))

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//// [tests/cases/conformance/controlFlow/dependentDestructuredVariablesNoCrash2.ts] ////

=== dependentDestructuredVariablesNoCrash2.ts ===
// https://github.com/microsoft/TypeScript/issues/63091

function ([undefined, unknown]: string | undefined = undefined)
> : ([undefined, unknown]?: string | undefined) => any
> : ^ ^^^ ^^^^^^^^
>undefined : any
> : ^^^
>unknown : any
> : ^^^
>undefined : any
> : ^^^

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
dependentDestructuredVariablesNoCrash3.ts(3,7): error TS2488: Type 'boolean' must have a '[Symbol.iterator]()' method that returns an iterator.
dependentDestructuredVariablesNoCrash3.ts(3,30): error TS7022: 'string' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
dependentDestructuredVariablesNoCrash3.ts(3,69): error TS2582: Cannot find name 'test'. Do you need to install type definitions for a test runner? Try `npm i --save-dev @types/jest` or `npm i --save-dev @types/mocha`.
dependentDestructuredVariablesNoCrash3.ts(3,86): error TS2448: Block-scoped variable 'string' used before its declaration.
dependentDestructuredVariablesNoCrash3.ts(3,95): error TS1109: Expression expected.
dependentDestructuredVariablesNoCrash3.ts(3,97): error TS2339: Property 'ranges' does not exist on type 'boolean'.


==== dependentDestructuredVariablesNoCrash3.ts (6 errors) ====
// https://github.com/microsoft/TypeScript/issues/63093

const [r0Def, r0, r1Def, as, string, r1, r2, r3Def, r3]: boolean = (test as number < string > ).ranges();
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2488: Type 'boolean' must have a '[Symbol.iterator]()' method that returns an iterator.
~~~~~~
!!! error TS7022: 'string' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
~~~~
!!! error TS2582: Cannot find name 'test'. Do you need to install type definitions for a test runner? Try `npm i --save-dev @types/jest` or `npm i --save-dev @types/mocha`.
~~~~~~
!!! error TS2448: Block-scoped variable 'string' used before its declaration.
!!! related TS2728 dependentDestructuredVariablesNoCrash3.ts:3:30: 'string' is declared here.
~
!!! error TS1109: Expression expected.
~~~~~~
!!! error TS2339: Property 'ranges' does not exist on type 'boolean'.

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//// [tests/cases/conformance/controlFlow/dependentDestructuredVariablesNoCrash3.ts] ////

//// [dependentDestructuredVariablesNoCrash3.ts]
// https://github.com/microsoft/TypeScript/issues/63093

const [r0Def, r0, r1Def, as, string, r1, r2, r3Def, r3]: boolean = (test as number < string > ).ranges();


//// [dependentDestructuredVariablesNoCrash3.js]
"use strict";
// https://github.com/microsoft/TypeScript/issues/63093
const [r0Def, r0, r1Def, as, string, r1, r2, r3Def, r3] = (test < string > ).ranges();


//// [dependentDestructuredVariablesNoCrash3.d.ts]
declare const r0Def: any, r0: any, r1Def: any, as: any, string: any, r1: any, r2: any, r3Def: any, r3: any;
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//// [tests/cases/conformance/controlFlow/dependentDestructuredVariablesNoCrash3.ts] ////

=== dependentDestructuredVariablesNoCrash3.ts ===
// https://github.com/microsoft/TypeScript/issues/63093

const [r0Def, r0, r1Def, as, string, r1, r2, r3Def, r3]: boolean = (test as number < string > ).ranges();
>r0Def : Symbol(r0Def, Decl(dependentDestructuredVariablesNoCrash3.ts, 2, 7))
>r0 : Symbol(r0, Decl(dependentDestructuredVariablesNoCrash3.ts, 2, 13))
>r1Def : Symbol(r1Def, Decl(dependentDestructuredVariablesNoCrash3.ts, 2, 17))
>as : Symbol(as, Decl(dependentDestructuredVariablesNoCrash3.ts, 2, 24))
>string : Symbol(string, Decl(dependentDestructuredVariablesNoCrash3.ts, 2, 28))
>r1 : Symbol(r1, Decl(dependentDestructuredVariablesNoCrash3.ts, 2, 36))
>r2 : Symbol(r2, Decl(dependentDestructuredVariablesNoCrash3.ts, 2, 40))
>r3Def : Symbol(r3Def, Decl(dependentDestructuredVariablesNoCrash3.ts, 2, 44))
>r3 : Symbol(r3, Decl(dependentDestructuredVariablesNoCrash3.ts, 2, 51))
>string : Symbol(string, Decl(dependentDestructuredVariablesNoCrash3.ts, 2, 28))

Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//// [tests/cases/conformance/controlFlow/dependentDestructuredVariablesNoCrash3.ts] ////

=== dependentDestructuredVariablesNoCrash3.ts ===
// https://github.com/microsoft/TypeScript/issues/63093

const [r0Def, r0, r1Def, as, string, r1, r2, r3Def, r3]: boolean = (test as number < string > ).ranges();
>r0Def : any
> : ^^^
>r0 : any
> : ^^^
>r1Def : any
> : ^^^
>as : any
> : ^^^
>string : any
> : ^^^
>r1 : any
> : ^^^
>r2 : any
> : ^^^
>r3Def : any
> : ^^^
>r3 : any
> : ^^^
>(test as number < string > ).ranges() : any
> : ^^^
>(test as number < string > ).ranges : any
> : ^^^
>(test as number < string > ) : boolean
> : ^^^^^^^
>test as number < string > : boolean
> : ^^^^^^^
>test as number < string : boolean
> : ^^^^^^^
>test as number : number
> : ^^^^^^
>test : any
> : ^^^
>string : any
> : ^^^
> : any
> : ^^^
>ranges : any
> : ^^^

Loading