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
4 changes: 2 additions & 2 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29475,7 +29475,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (isIdentifier(expr)) {
const symbol = getResolvedSymbol(expr);
const declaration = getExportSymbolOfValueSymbolIfExported(symbol).valueDeclaration;
if (declaration && (isBindingElement(declaration) || isParameter(declaration)) && reference === declaration.parent && !declaration.initializer && !declaration.dotDotDotToken) {
if (declaration && (isBindingElement(declaration) || isParameter(declaration)) && reference === declaration.parent && !declaration.dotDotDotToken) {
return declaration;
}
}
Expand Down Expand Up @@ -30947,7 +30947,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// the binding pattern AST instance for '{ kind, payload }' as a pseudo-reference and narrow this reference
// as if it occurred in the specified location. We then recompute the narrowed binding element type by
// destructuring from the narrowed parent type.
if (isBindingElement(declaration) && !declaration.initializer && !declaration.dotDotDotToken && declaration.parent.elements.length >= 2) {
if (isBindingElement(declaration) && !declaration.dotDotDotToken && declaration.parent.elements.length >= 2) {
const parent = declaration.parent.parent;
const rootDeclaration = getRootDeclaration(parent);
if (rootDeclaration.kind === SyntaxKind.VariableDeclaration && getCombinedNodeFlagsCached(rootDeclaration) & NodeFlags.Constant || rootDeclaration.kind === SyntaxKind.Parameter) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
discriminatedUnionDestructuringWithDefaults.ts(26,43): error TS2322: Type 'boolean' is not assignable to type 'string | number'.


==== discriminatedUnionDestructuringWithDefaults.ts (1 errors) ====
// Case 1: the issue #50139 repro — must compile clean after the fix
function repro({ isText = false, children = 0 }:
{ isText: true; children?: string }
| { isText: false; children?: number }
) {
if (isText === true) {
let data: string = children;
} else if (isText === false) {
let data: number = children;
}
}

// Case 2: control — no defaults, already worked, must not regress
function control({ isText, children }:
{ isText: true; children: string }
| { isText: false; children: number }
) {
if (isText === true) {
let data: string = children;
} else if (isText === false) {
let data: number = children;
}
}

// Case 3: whzx5byb's soundness check — default foreign to one arm must still error
function soundnessCheck({ isText = false, children = true }: // expect error on `children = true`
~~~~~~~~
!!! error TS2322: Type 'boolean' is not assignable to type 'string | number'.
{ isText: true; children?: string }
| { isText: false; children?: number }
) {
if (isText === true) {
let data: string = children;
}
}

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

//// [discriminatedUnionDestructuringWithDefaults.ts]
// Case 1: the issue #50139 repro — must compile clean after the fix
function repro({ isText = false, children = 0 }:
{ isText: true; children?: string }
| { isText: false; children?: number }
) {
if (isText === true) {
let data: string = children;
} else if (isText === false) {
let data: number = children;
}
}

// Case 2: control — no defaults, already worked, must not regress
function control({ isText, children }:
{ isText: true; children: string }
| { isText: false; children: number }
) {
if (isText === true) {
let data: string = children;
} else if (isText === false) {
let data: number = children;
}
}

// Case 3: whzx5byb's soundness check — default foreign to one arm must still error
function soundnessCheck({ isText = false, children = true }: // expect error on `children = true`
{ isText: true; children?: string }
| { isText: false; children?: number }
) {
if (isText === true) {
let data: string = children;
}
}


//// [discriminatedUnionDestructuringWithDefaults.js]
"use strict";
// Case 1: the issue #50139 repro — must compile clean after the fix
function repro({ isText = false, children = 0 }) {
if (isText === true) {
let data = children;
}
else if (isText === false) {
let data = children;
}
}
// Case 2: control — no defaults, already worked, must not regress
function control({ isText, children }) {
if (isText === true) {
let data = children;
}
else if (isText === false) {
let data = children;
}
}
// Case 3: whzx5byb's soundness check — default foreign to one arm must still error
function soundnessCheck({ isText = false, children = true }) {
if (isText === true) {
let data = children;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//// [tests/cases/compiler/discriminatedUnionDestructuringWithDefaults.ts] ////

=== discriminatedUnionDestructuringWithDefaults.ts ===
// Case 1: the issue #50139 repro — must compile clean after the fix
function repro({ isText = false, children = 0 }:
>repro : Symbol(repro, Decl(discriminatedUnionDestructuringWithDefaults.ts, 0, 0))
>isText : Symbol(isText, Decl(discriminatedUnionDestructuringWithDefaults.ts, 1, 16))
>children : Symbol(children, Decl(discriminatedUnionDestructuringWithDefaults.ts, 1, 32))

{ isText: true; children?: string }
>isText : Symbol(isText, Decl(discriminatedUnionDestructuringWithDefaults.ts, 2, 5))
>children : Symbol(children, Decl(discriminatedUnionDestructuringWithDefaults.ts, 2, 19))

| { isText: false; children?: number }
>isText : Symbol(isText, Decl(discriminatedUnionDestructuringWithDefaults.ts, 3, 5))
>children : Symbol(children, Decl(discriminatedUnionDestructuringWithDefaults.ts, 3, 20))

) {
if (isText === true) {
>isText : Symbol(isText, Decl(discriminatedUnionDestructuringWithDefaults.ts, 1, 16))

let data: string = children;
>data : Symbol(data, Decl(discriminatedUnionDestructuringWithDefaults.ts, 6, 11))
>children : Symbol(children, Decl(discriminatedUnionDestructuringWithDefaults.ts, 1, 32))

} else if (isText === false) {
>isText : Symbol(isText, Decl(discriminatedUnionDestructuringWithDefaults.ts, 1, 16))

let data: number = children;
>data : Symbol(data, Decl(discriminatedUnionDestructuringWithDefaults.ts, 8, 11))
>children : Symbol(children, Decl(discriminatedUnionDestructuringWithDefaults.ts, 1, 32))
}
}

// Case 2: control — no defaults, already worked, must not regress
function control({ isText, children }:
>control : Symbol(control, Decl(discriminatedUnionDestructuringWithDefaults.ts, 10, 1))
>isText : Symbol(isText, Decl(discriminatedUnionDestructuringWithDefaults.ts, 13, 18))
>children : Symbol(children, Decl(discriminatedUnionDestructuringWithDefaults.ts, 13, 26))

{ isText: true; children: string }
>isText : Symbol(isText, Decl(discriminatedUnionDestructuringWithDefaults.ts, 14, 5))
>children : Symbol(children, Decl(discriminatedUnionDestructuringWithDefaults.ts, 14, 19))

| { isText: false; children: number }
>isText : Symbol(isText, Decl(discriminatedUnionDestructuringWithDefaults.ts, 15, 5))
>children : Symbol(children, Decl(discriminatedUnionDestructuringWithDefaults.ts, 15, 20))

) {
if (isText === true) {
>isText : Symbol(isText, Decl(discriminatedUnionDestructuringWithDefaults.ts, 13, 18))

let data: string = children;
>data : Symbol(data, Decl(discriminatedUnionDestructuringWithDefaults.ts, 18, 11))
>children : Symbol(children, Decl(discriminatedUnionDestructuringWithDefaults.ts, 13, 26))

} else if (isText === false) {
>isText : Symbol(isText, Decl(discriminatedUnionDestructuringWithDefaults.ts, 13, 18))

let data: number = children;
>data : Symbol(data, Decl(discriminatedUnionDestructuringWithDefaults.ts, 20, 11))
>children : Symbol(children, Decl(discriminatedUnionDestructuringWithDefaults.ts, 13, 26))
}
}

// Case 3: whzx5byb's soundness check — default foreign to one arm must still error
function soundnessCheck({ isText = false, children = true }: // expect error on `children = true`
>soundnessCheck : Symbol(soundnessCheck, Decl(discriminatedUnionDestructuringWithDefaults.ts, 22, 1))
>isText : Symbol(isText, Decl(discriminatedUnionDestructuringWithDefaults.ts, 25, 25))
>children : Symbol(children, Decl(discriminatedUnionDestructuringWithDefaults.ts, 25, 41))

{ isText: true; children?: string }
>isText : Symbol(isText, Decl(discriminatedUnionDestructuringWithDefaults.ts, 26, 5))
>children : Symbol(children, Decl(discriminatedUnionDestructuringWithDefaults.ts, 26, 19))

| { isText: false; children?: number }
>isText : Symbol(isText, Decl(discriminatedUnionDestructuringWithDefaults.ts, 27, 5))
>children : Symbol(children, Decl(discriminatedUnionDestructuringWithDefaults.ts, 27, 20))

) {
if (isText === true) {
>isText : Symbol(isText, Decl(discriminatedUnionDestructuringWithDefaults.ts, 25, 25))

let data: string = children;
>data : Symbol(data, Decl(discriminatedUnionDestructuringWithDefaults.ts, 30, 11))
>children : Symbol(children, Decl(discriminatedUnionDestructuringWithDefaults.ts, 25, 41))
}
}

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

=== discriminatedUnionDestructuringWithDefaults.ts ===
// Case 1: the issue #50139 repro — must compile clean after the fix
function repro({ isText = false, children = 0 }:
>repro : ({ isText, children }: { isText: true; children?: string; } | { isText: false; children?: number; }) => void
> : ^ ^^ ^^^^^^^^^
>isText : boolean
> : ^^^^^^^
>false : false
> : ^^^^^
>children : string | number
> : ^^^^^^^^^^^^^^^
>0 : 0
> : ^

{ isText: true; children?: string }
>isText : true
> : ^^^^
>true : true
> : ^^^^
>children : string | undefined
> : ^^^^^^^^^^^^^^^^^^

| { isText: false; children?: number }
>isText : false
> : ^^^^^
>false : false
> : ^^^^^
>children : number | undefined
> : ^^^^^^^^^^^^^^^^^^

) {
if (isText === true) {
>isText === true : boolean
> : ^^^^^^^
>isText : boolean
> : ^^^^^^^
>true : true
> : ^^^^

let data: string = children;
>data : string
> : ^^^^^^
>children : string
> : ^^^^^^

} else if (isText === false) {
>isText === false : boolean
> : ^^^^^^^
>isText : false
> : ^^^^^
>false : false
> : ^^^^^

let data: number = children;
>data : number
> : ^^^^^^
>children : number
> : ^^^^^^
}
}

// Case 2: control — no defaults, already worked, must not regress
function control({ isText, children }:
>control : ({ isText, children }: { isText: true; children: string; } | { isText: false; children: number; }) => void
> : ^ ^^ ^^^^^^^^^
>isText : boolean
> : ^^^^^^^
>children : string | number
> : ^^^^^^^^^^^^^^^

{ isText: true; children: string }
>isText : true
> : ^^^^
>true : true
> : ^^^^
>children : string
> : ^^^^^^

| { isText: false; children: number }
>isText : false
> : ^^^^^
>false : false
> : ^^^^^
>children : number
> : ^^^^^^

) {
if (isText === true) {
>isText === true : boolean
> : ^^^^^^^
>isText : boolean
> : ^^^^^^^
>true : true
> : ^^^^

let data: string = children;
>data : string
> : ^^^^^^
>children : string
> : ^^^^^^

} else if (isText === false) {
>isText === false : boolean
> : ^^^^^^^
>isText : false
> : ^^^^^
>false : false
> : ^^^^^

let data: number = children;
>data : number
> : ^^^^^^
>children : number
> : ^^^^^^
}
}

// Case 3: whzx5byb's soundness check — default foreign to one arm must still error
function soundnessCheck({ isText = false, children = true }: // expect error on `children = true`
>soundnessCheck : ({ isText, children }: { isText: true; children?: string; } | { isText: false; children?: number; }) => void
> : ^ ^^ ^^^^^^^^^
>isText : boolean
> : ^^^^^^^
>false : false
> : ^^^^^
>children : string | number
> : ^^^^^^^^^^^^^^^
>true : true
> : ^^^^

{ isText: true; children?: string }
>isText : true
> : ^^^^
>true : true
> : ^^^^
>children : string | undefined
> : ^^^^^^^^^^^^^^^^^^

| { isText: false; children?: number }
>isText : false
> : ^^^^^
>false : false
> : ^^^^^
>children : number | undefined
> : ^^^^^^^^^^^^^^^^^^

) {
if (isText === true) {
>isText === true : boolean
> : ^^^^^^^
>isText : boolean
> : ^^^^^^^
>true : true
> : ^^^^

let data: string = children;
>data : string
> : ^^^^^^
>children : string
> : ^^^^^^
}
}

Loading