Fix stack overflow in JSX discriminated union logic (#46354)
* Use getContextFreeTypeOfExpression to avoid circularities * Add regression test
This commit is contained in:
parent
5185ef55e3
commit
8718df3dc1
|
@ -22691,7 +22691,7 @@ namespace ts {
|
|||
const keyPropertyName = getKeyPropertyName(unionType);
|
||||
const propNode = keyPropertyName && find(node.properties, p => p.symbol && p.kind === SyntaxKind.PropertyAssignment &&
|
||||
p.symbol.escapedName === keyPropertyName && isPossiblyDiscriminantValue(p.initializer));
|
||||
const propType = propNode && getTypeOfExpression((propNode as PropertyAssignment).initializer);
|
||||
const propType = propNode && getContextFreeTypeOfExpression((propNode as PropertyAssignment).initializer);
|
||||
return propType && getConstituentTypeForKeyType(unionType, propType);
|
||||
}
|
||||
|
||||
|
@ -26198,7 +26198,7 @@ namespace ts {
|
|||
concatenate(
|
||||
map(
|
||||
filter(node.properties, p => !!p.symbol && p.kind === SyntaxKind.JsxAttribute && isDiscriminantProperty(contextualType, p.symbol.escapedName) && (!p.initializer || isPossiblyDiscriminantValue(p.initializer))),
|
||||
prop => ([!(prop as JsxAttribute).initializer ? (() => trueType) : (() => checkExpression((prop as JsxAttribute).initializer!)), prop.symbol.escapedName] as [() => Type, __String])
|
||||
prop => ([!(prop as JsxAttribute).initializer ? (() => trueType) : (() => getContextFreeTypeOfExpression((prop as JsxAttribute).initializer!)), prop.symbol.escapedName] as [() => Type, __String])
|
||||
),
|
||||
map(
|
||||
filter(getPropertiesOfType(contextualType), s => !!(s.flags & SymbolFlags.Optional) && !!node?.symbol?.members && !node.symbol.members.has(s.escapedName) && isDiscriminantProperty(contextualType, s.escapedName)),
|
||||
|
|
57
tests/baselines/reference/discriminatedUnionJsxElement.js
Normal file
57
tests/baselines/reference/discriminatedUnionJsxElement.js
Normal file
|
@ -0,0 +1,57 @@
|
|||
//// [discriminatedUnionJsxElement.tsx]
|
||||
// Repro from #46021
|
||||
|
||||
interface IData<MenuItemVariant extends ListItemVariant = ListItemVariant.OneLine> {
|
||||
menuItemsVariant?: MenuItemVariant;
|
||||
}
|
||||
|
||||
function Menu<MenuItemVariant extends ListItemVariant = ListItemVariant.OneLine>(data: IData<MenuItemVariant>) {
|
||||
const listItemVariant = data.menuItemsVariant ?? ListItemVariant.OneLine;
|
||||
return <ListItem variant={listItemVariant} />;
|
||||
}
|
||||
|
||||
type IListItemData = { variant: ListItemVariant.Avatar; } | { variant: ListItemVariant.OneLine; };
|
||||
|
||||
enum ListItemVariant {
|
||||
OneLine,
|
||||
Avatar,
|
||||
}
|
||||
|
||||
function ListItem(_data: IListItemData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
//// [discriminatedUnionJsxElement.jsx]
|
||||
"use strict";
|
||||
// Repro from #46021
|
||||
function Menu(data) {
|
||||
var _a;
|
||||
var listItemVariant = (_a = data.menuItemsVariant) !== null && _a !== void 0 ? _a : ListItemVariant.OneLine;
|
||||
return <ListItem variant={listItemVariant}/>;
|
||||
}
|
||||
var ListItemVariant;
|
||||
(function (ListItemVariant) {
|
||||
ListItemVariant[ListItemVariant["OneLine"] = 0] = "OneLine";
|
||||
ListItemVariant[ListItemVariant["Avatar"] = 1] = "Avatar";
|
||||
})(ListItemVariant || (ListItemVariant = {}));
|
||||
function ListItem(_data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
//// [discriminatedUnionJsxElement.d.ts]
|
||||
interface IData<MenuItemVariant extends ListItemVariant = ListItemVariant.OneLine> {
|
||||
menuItemsVariant?: MenuItemVariant;
|
||||
}
|
||||
declare function Menu<MenuItemVariant extends ListItemVariant = ListItemVariant.OneLine>(data: IData<MenuItemVariant>): any;
|
||||
declare type IListItemData = {
|
||||
variant: ListItemVariant.Avatar;
|
||||
} | {
|
||||
variant: ListItemVariant.OneLine;
|
||||
};
|
||||
declare enum ListItemVariant {
|
||||
OneLine = 0,
|
||||
Avatar = 1
|
||||
}
|
||||
declare function ListItem(_data: IListItemData): null;
|
|
@ -0,0 +1,67 @@
|
|||
=== tests/cases/compiler/discriminatedUnionJsxElement.tsx ===
|
||||
// Repro from #46021
|
||||
|
||||
interface IData<MenuItemVariant extends ListItemVariant = ListItemVariant.OneLine> {
|
||||
>IData : Symbol(IData, Decl(discriminatedUnionJsxElement.tsx, 0, 0))
|
||||
>MenuItemVariant : Symbol(MenuItemVariant, Decl(discriminatedUnionJsxElement.tsx, 2, 16))
|
||||
>ListItemVariant : Symbol(ListItemVariant, Decl(discriminatedUnionJsxElement.tsx, 11, 98))
|
||||
>ListItemVariant : Symbol(ListItemVariant, Decl(discriminatedUnionJsxElement.tsx, 11, 98))
|
||||
>OneLine : Symbol(ListItemVariant.OneLine, Decl(discriminatedUnionJsxElement.tsx, 13, 22))
|
||||
|
||||
menuItemsVariant?: MenuItemVariant;
|
||||
>menuItemsVariant : Symbol(IData.menuItemsVariant, Decl(discriminatedUnionJsxElement.tsx, 2, 84))
|
||||
>MenuItemVariant : Symbol(MenuItemVariant, Decl(discriminatedUnionJsxElement.tsx, 2, 16))
|
||||
}
|
||||
|
||||
function Menu<MenuItemVariant extends ListItemVariant = ListItemVariant.OneLine>(data: IData<MenuItemVariant>) {
|
||||
>Menu : Symbol(Menu, Decl(discriminatedUnionJsxElement.tsx, 4, 1))
|
||||
>MenuItemVariant : Symbol(MenuItemVariant, Decl(discriminatedUnionJsxElement.tsx, 6, 14))
|
||||
>ListItemVariant : Symbol(ListItemVariant, Decl(discriminatedUnionJsxElement.tsx, 11, 98))
|
||||
>ListItemVariant : Symbol(ListItemVariant, Decl(discriminatedUnionJsxElement.tsx, 11, 98))
|
||||
>OneLine : Symbol(ListItemVariant.OneLine, Decl(discriminatedUnionJsxElement.tsx, 13, 22))
|
||||
>data : Symbol(data, Decl(discriminatedUnionJsxElement.tsx, 6, 81))
|
||||
>IData : Symbol(IData, Decl(discriminatedUnionJsxElement.tsx, 0, 0))
|
||||
>MenuItemVariant : Symbol(MenuItemVariant, Decl(discriminatedUnionJsxElement.tsx, 6, 14))
|
||||
|
||||
const listItemVariant = data.menuItemsVariant ?? ListItemVariant.OneLine;
|
||||
>listItemVariant : Symbol(listItemVariant, Decl(discriminatedUnionJsxElement.tsx, 7, 9))
|
||||
>data.menuItemsVariant : Symbol(IData.menuItemsVariant, Decl(discriminatedUnionJsxElement.tsx, 2, 84))
|
||||
>data : Symbol(data, Decl(discriminatedUnionJsxElement.tsx, 6, 81))
|
||||
>menuItemsVariant : Symbol(IData.menuItemsVariant, Decl(discriminatedUnionJsxElement.tsx, 2, 84))
|
||||
>ListItemVariant.OneLine : Symbol(ListItemVariant.OneLine, Decl(discriminatedUnionJsxElement.tsx, 13, 22))
|
||||
>ListItemVariant : Symbol(ListItemVariant, Decl(discriminatedUnionJsxElement.tsx, 11, 98))
|
||||
>OneLine : Symbol(ListItemVariant.OneLine, Decl(discriminatedUnionJsxElement.tsx, 13, 22))
|
||||
|
||||
return <ListItem variant={listItemVariant} />;
|
||||
>ListItem : Symbol(ListItem, Decl(discriminatedUnionJsxElement.tsx, 16, 1))
|
||||
>variant : Symbol(variant, Decl(discriminatedUnionJsxElement.tsx, 8, 20))
|
||||
>listItemVariant : Symbol(listItemVariant, Decl(discriminatedUnionJsxElement.tsx, 7, 9))
|
||||
}
|
||||
|
||||
type IListItemData = { variant: ListItemVariant.Avatar; } | { variant: ListItemVariant.OneLine; };
|
||||
>IListItemData : Symbol(IListItemData, Decl(discriminatedUnionJsxElement.tsx, 9, 1))
|
||||
>variant : Symbol(variant, Decl(discriminatedUnionJsxElement.tsx, 11, 22))
|
||||
>ListItemVariant : Symbol(ListItemVariant, Decl(discriminatedUnionJsxElement.tsx, 11, 98))
|
||||
>Avatar : Symbol(ListItemVariant.Avatar, Decl(discriminatedUnionJsxElement.tsx, 14, 12))
|
||||
>variant : Symbol(variant, Decl(discriminatedUnionJsxElement.tsx, 11, 61))
|
||||
>ListItemVariant : Symbol(ListItemVariant, Decl(discriminatedUnionJsxElement.tsx, 11, 98))
|
||||
>OneLine : Symbol(ListItemVariant.OneLine, Decl(discriminatedUnionJsxElement.tsx, 13, 22))
|
||||
|
||||
enum ListItemVariant {
|
||||
>ListItemVariant : Symbol(ListItemVariant, Decl(discriminatedUnionJsxElement.tsx, 11, 98))
|
||||
|
||||
OneLine,
|
||||
>OneLine : Symbol(ListItemVariant.OneLine, Decl(discriminatedUnionJsxElement.tsx, 13, 22))
|
||||
|
||||
Avatar,
|
||||
>Avatar : Symbol(ListItemVariant.Avatar, Decl(discriminatedUnionJsxElement.tsx, 14, 12))
|
||||
}
|
||||
|
||||
function ListItem(_data: IListItemData) {
|
||||
>ListItem : Symbol(ListItem, Decl(discriminatedUnionJsxElement.tsx, 16, 1))
|
||||
>_data : Symbol(_data, Decl(discriminatedUnionJsxElement.tsx, 18, 18))
|
||||
>IListItemData : Symbol(IListItemData, Decl(discriminatedUnionJsxElement.tsx, 9, 1))
|
||||
|
||||
return null;
|
||||
}
|
||||
|
57
tests/baselines/reference/discriminatedUnionJsxElement.types
Normal file
57
tests/baselines/reference/discriminatedUnionJsxElement.types
Normal file
|
@ -0,0 +1,57 @@
|
|||
=== tests/cases/compiler/discriminatedUnionJsxElement.tsx ===
|
||||
// Repro from #46021
|
||||
|
||||
interface IData<MenuItemVariant extends ListItemVariant = ListItemVariant.OneLine> {
|
||||
>ListItemVariant : any
|
||||
|
||||
menuItemsVariant?: MenuItemVariant;
|
||||
>menuItemsVariant : MenuItemVariant | undefined
|
||||
}
|
||||
|
||||
function Menu<MenuItemVariant extends ListItemVariant = ListItemVariant.OneLine>(data: IData<MenuItemVariant>) {
|
||||
>Menu : <MenuItemVariant extends ListItemVariant = ListItemVariant.OneLine>(data: IData<MenuItemVariant>) => any
|
||||
>ListItemVariant : any
|
||||
>data : IData<MenuItemVariant>
|
||||
|
||||
const listItemVariant = data.menuItemsVariant ?? ListItemVariant.OneLine;
|
||||
>listItemVariant : ListItemVariant.OneLine | NonNullable<MenuItemVariant>
|
||||
>data.menuItemsVariant ?? ListItemVariant.OneLine : ListItemVariant.OneLine | NonNullable<MenuItemVariant>
|
||||
>data.menuItemsVariant : MenuItemVariant | undefined
|
||||
>data : IData<MenuItemVariant>
|
||||
>menuItemsVariant : MenuItemVariant | undefined
|
||||
>ListItemVariant.OneLine : ListItemVariant.OneLine
|
||||
>ListItemVariant : typeof ListItemVariant
|
||||
>OneLine : ListItemVariant.OneLine
|
||||
|
||||
return <ListItem variant={listItemVariant} />;
|
||||
><ListItem variant={listItemVariant} /> : error
|
||||
>ListItem : (_data: IListItemData) => null
|
||||
>variant : ListItemVariant
|
||||
>listItemVariant : ListItemVariant
|
||||
}
|
||||
|
||||
type IListItemData = { variant: ListItemVariant.Avatar; } | { variant: ListItemVariant.OneLine; };
|
||||
>IListItemData : IListItemData
|
||||
>variant : ListItemVariant.Avatar
|
||||
>ListItemVariant : any
|
||||
>variant : ListItemVariant.OneLine
|
||||
>ListItemVariant : any
|
||||
|
||||
enum ListItemVariant {
|
||||
>ListItemVariant : ListItemVariant
|
||||
|
||||
OneLine,
|
||||
>OneLine : ListItemVariant.OneLine
|
||||
|
||||
Avatar,
|
||||
>Avatar : ListItemVariant.Avatar
|
||||
}
|
||||
|
||||
function ListItem(_data: IListItemData) {
|
||||
>ListItem : (_data: IListItemData) => null
|
||||
>_data : IListItemData
|
||||
|
||||
return null;
|
||||
>null : null
|
||||
}
|
||||
|
25
tests/cases/compiler/discriminatedUnionJsxElement.tsx
Normal file
25
tests/cases/compiler/discriminatedUnionJsxElement.tsx
Normal file
|
@ -0,0 +1,25 @@
|
|||
// @strict: true
|
||||
// @declaration: true
|
||||
// @jsx: preserve
|
||||
|
||||
// Repro from #46021
|
||||
|
||||
interface IData<MenuItemVariant extends ListItemVariant = ListItemVariant.OneLine> {
|
||||
menuItemsVariant?: MenuItemVariant;
|
||||
}
|
||||
|
||||
function Menu<MenuItemVariant extends ListItemVariant = ListItemVariant.OneLine>(data: IData<MenuItemVariant>) {
|
||||
const listItemVariant = data.menuItemsVariant ?? ListItemVariant.OneLine;
|
||||
return <ListItem variant={listItemVariant} />;
|
||||
}
|
||||
|
||||
type IListItemData = { variant: ListItemVariant.Avatar; } | { variant: ListItemVariant.OneLine; };
|
||||
|
||||
enum ListItemVariant {
|
||||
OneLine,
|
||||
Avatar,
|
||||
}
|
||||
|
||||
function ListItem(_data: IListItemData) {
|
||||
return null;
|
||||
}
|
Loading…
Reference in a new issue