-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Optimize intersections of unions of unit types #24137
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3674,6 +3674,8 @@ namespace ts { | |
ContainsAnyFunctionType = 1 << 26, // Type is or contains the anyFunctionType | ||
NonPrimitive = 1 << 27, // intrinsic object type | ||
/* @internal */ | ||
UnionOfUnitTypes = 1 << 28, // Type is union of unit types | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With this, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, |
||
/* @internal */ | ||
GenericMappedType = 1 << 29, // Flag used by maybeTypeOfKind | ||
|
||
/* @internal */ | ||
|
@@ -3711,6 +3713,8 @@ namespace ts { | |
Narrowable = Any | StructuredOrInstantiable | StringLike | NumberLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive, | ||
NotUnionOrUnit = Any | ESSymbol | Object | NonPrimitive, | ||
/* @internal */ | ||
NotUnit = Any | String | Number | Boolean | Enum | ESSymbol | Void | Never | StructuredOrInstantiable, | ||
/* @internal */ | ||
RequiresWidening = ContainsWideningType | ContainsObjectLiteral, | ||
/* @internal */ | ||
PropagatingFlags = ContainsWideningType | ContainsObjectLiteral | ContainsAnyFunctionType, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
tests/cases/compiler/intersectionsOfLargeUnions.ts(21,15): error TS2536: Type 'T' cannot be used to index type 'HTMLElementTagNameMap'. | ||
tests/cases/compiler/intersectionsOfLargeUnions.ts(21,15): error TS2536: Type 'P' cannot be used to index type 'HTMLElementTagNameMap[T]'. | ||
|
||
|
||
==== tests/cases/compiler/intersectionsOfLargeUnions.ts (2 errors) ==== | ||
// Repro from #23977 | ||
|
||
export function assertIsElement(node: Node | null): node is Element { | ||
let nodeType = node === null ? null : node.nodeType; | ||
return nodeType === 1; | ||
} | ||
|
||
export function assertNodeTagName< | ||
T extends keyof ElementTagNameMap, | ||
U extends ElementTagNameMap[T]>(node: Node | null, tagName: T): node is U { | ||
if (assertIsElement(node)) { | ||
const nodeTagName = node.tagName.toLowerCase(); | ||
return nodeTagName === tagName; | ||
} | ||
return false; | ||
} | ||
|
||
export function assertNodeProperty< | ||
T extends keyof ElementTagNameMap, | ||
P extends keyof ElementTagNameMap[T], | ||
V extends HTMLElementTagNameMap[T][P]>(node: Node | null, tagName: T, prop: P, value: V) { | ||
~~~~~~~~~~~~~~~~~~~~~~~~ | ||
!!! error TS2536: Type 'T' cannot be used to index type 'HTMLElementTagNameMap'. | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
!!! error TS2536: Type 'P' cannot be used to index type 'HTMLElementTagNameMap[T]'. | ||
if (assertNodeTagName(node, tagName)) { | ||
node[prop]; | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
//// [intersectionsOfLargeUnions.ts] | ||
// Repro from #23977 | ||
|
||
export function assertIsElement(node: Node | null): node is Element { | ||
let nodeType = node === null ? null : node.nodeType; | ||
return nodeType === 1; | ||
} | ||
|
||
export function assertNodeTagName< | ||
T extends keyof ElementTagNameMap, | ||
U extends ElementTagNameMap[T]>(node: Node | null, tagName: T): node is U { | ||
if (assertIsElement(node)) { | ||
const nodeTagName = node.tagName.toLowerCase(); | ||
return nodeTagName === tagName; | ||
} | ||
return false; | ||
} | ||
|
||
export function assertNodeProperty< | ||
T extends keyof ElementTagNameMap, | ||
P extends keyof ElementTagNameMap[T], | ||
V extends HTMLElementTagNameMap[T][P]>(node: Node | null, tagName: T, prop: P, value: V) { | ||
if (assertNodeTagName(node, tagName)) { | ||
node[prop]; | ||
} | ||
} | ||
|
||
|
||
//// [intersectionsOfLargeUnions.js] | ||
"use strict"; | ||
// Repro from #23977 | ||
exports.__esModule = true; | ||
function assertIsElement(node) { | ||
var nodeType = node === null ? null : node.nodeType; | ||
return nodeType === 1; | ||
} | ||
exports.assertIsElement = assertIsElement; | ||
function assertNodeTagName(node, tagName) { | ||
if (assertIsElement(node)) { | ||
var nodeTagName = node.tagName.toLowerCase(); | ||
return nodeTagName === tagName; | ||
} | ||
return false; | ||
} | ||
exports.assertNodeTagName = assertNodeTagName; | ||
function assertNodeProperty(node, tagName, prop, value) { | ||
if (assertNodeTagName(node, tagName)) { | ||
node[prop]; | ||
} | ||
} | ||
exports.assertNodeProperty = assertNodeProperty; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
=== tests/cases/compiler/intersectionsOfLargeUnions.ts === | ||
// Repro from #23977 | ||
|
||
export function assertIsElement(node: Node | null): node is Element { | ||
>assertIsElement : Symbol(assertIsElement, Decl(intersectionsOfLargeUnions.ts, 0, 0)) | ||
>node : Symbol(node, Decl(intersectionsOfLargeUnions.ts, 2, 32)) | ||
>Node : Symbol(Node, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) | ||
>node : Symbol(node, Decl(intersectionsOfLargeUnions.ts, 2, 32)) | ||
>Element : Symbol(Element, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) | ||
|
||
let nodeType = node === null ? null : node.nodeType; | ||
>nodeType : Symbol(nodeType, Decl(intersectionsOfLargeUnions.ts, 3, 7)) | ||
>node : Symbol(node, Decl(intersectionsOfLargeUnions.ts, 2, 32)) | ||
>node.nodeType : Symbol(Node.nodeType, Decl(lib.d.ts, --, --)) | ||
>node : Symbol(node, Decl(intersectionsOfLargeUnions.ts, 2, 32)) | ||
>nodeType : Symbol(Node.nodeType, Decl(lib.d.ts, --, --)) | ||
|
||
return nodeType === 1; | ||
>nodeType : Symbol(nodeType, Decl(intersectionsOfLargeUnions.ts, 3, 7)) | ||
} | ||
|
||
export function assertNodeTagName< | ||
>assertNodeTagName : Symbol(assertNodeTagName, Decl(intersectionsOfLargeUnions.ts, 5, 1)) | ||
|
||
T extends keyof ElementTagNameMap, | ||
>T : Symbol(T, Decl(intersectionsOfLargeUnions.ts, 7, 34)) | ||
>ElementTagNameMap : Symbol(ElementTagNameMap, Decl(lib.d.ts, --, --)) | ||
|
||
U extends ElementTagNameMap[T]>(node: Node | null, tagName: T): node is U { | ||
>U : Symbol(U, Decl(intersectionsOfLargeUnions.ts, 8, 38)) | ||
>ElementTagNameMap : Symbol(ElementTagNameMap, Decl(lib.d.ts, --, --)) | ||
>T : Symbol(T, Decl(intersectionsOfLargeUnions.ts, 7, 34)) | ||
>node : Symbol(node, Decl(intersectionsOfLargeUnions.ts, 9, 36)) | ||
>Node : Symbol(Node, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) | ||
>tagName : Symbol(tagName, Decl(intersectionsOfLargeUnions.ts, 9, 54)) | ||
>T : Symbol(T, Decl(intersectionsOfLargeUnions.ts, 7, 34)) | ||
>node : Symbol(node, Decl(intersectionsOfLargeUnions.ts, 9, 36)) | ||
>U : Symbol(U, Decl(intersectionsOfLargeUnions.ts, 8, 38)) | ||
|
||
if (assertIsElement(node)) { | ||
>assertIsElement : Symbol(assertIsElement, Decl(intersectionsOfLargeUnions.ts, 0, 0)) | ||
>node : Symbol(node, Decl(intersectionsOfLargeUnions.ts, 9, 36)) | ||
|
||
const nodeTagName = node.tagName.toLowerCase(); | ||
>nodeTagName : Symbol(nodeTagName, Decl(intersectionsOfLargeUnions.ts, 11, 13)) | ||
>node.tagName.toLowerCase : Symbol(String.toLowerCase, Decl(lib.d.ts, --, --)) | ||
>node.tagName : Symbol(Element.tagName, Decl(lib.d.ts, --, --)) | ||
>node : Symbol(node, Decl(intersectionsOfLargeUnions.ts, 9, 36)) | ||
>tagName : Symbol(Element.tagName, Decl(lib.d.ts, --, --)) | ||
>toLowerCase : Symbol(String.toLowerCase, Decl(lib.d.ts, --, --)) | ||
|
||
return nodeTagName === tagName; | ||
>nodeTagName : Symbol(nodeTagName, Decl(intersectionsOfLargeUnions.ts, 11, 13)) | ||
>tagName : Symbol(tagName, Decl(intersectionsOfLargeUnions.ts, 9, 54)) | ||
} | ||
return false; | ||
} | ||
|
||
export function assertNodeProperty< | ||
>assertNodeProperty : Symbol(assertNodeProperty, Decl(intersectionsOfLargeUnions.ts, 15, 1)) | ||
|
||
T extends keyof ElementTagNameMap, | ||
>T : Symbol(T, Decl(intersectionsOfLargeUnions.ts, 17, 35)) | ||
>ElementTagNameMap : Symbol(ElementTagNameMap, Decl(lib.d.ts, --, --)) | ||
|
||
P extends keyof ElementTagNameMap[T], | ||
>P : Symbol(P, Decl(intersectionsOfLargeUnions.ts, 18, 38)) | ||
>ElementTagNameMap : Symbol(ElementTagNameMap, Decl(lib.d.ts, --, --)) | ||
>T : Symbol(T, Decl(intersectionsOfLargeUnions.ts, 17, 35)) | ||
|
||
V extends HTMLElementTagNameMap[T][P]>(node: Node | null, tagName: T, prop: P, value: V) { | ||
>V : Symbol(V, Decl(intersectionsOfLargeUnions.ts, 19, 41)) | ||
>HTMLElementTagNameMap : Symbol(HTMLElementTagNameMap, Decl(lib.d.ts, --, --)) | ||
>T : Symbol(T, Decl(intersectionsOfLargeUnions.ts, 17, 35)) | ||
>P : Symbol(P, Decl(intersectionsOfLargeUnions.ts, 18, 38)) | ||
>node : Symbol(node, Decl(intersectionsOfLargeUnions.ts, 20, 43)) | ||
>Node : Symbol(Node, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) | ||
>tagName : Symbol(tagName, Decl(intersectionsOfLargeUnions.ts, 20, 61)) | ||
>T : Symbol(T, Decl(intersectionsOfLargeUnions.ts, 17, 35)) | ||
>prop : Symbol(prop, Decl(intersectionsOfLargeUnions.ts, 20, 73)) | ||
>P : Symbol(P, Decl(intersectionsOfLargeUnions.ts, 18, 38)) | ||
>value : Symbol(value, Decl(intersectionsOfLargeUnions.ts, 20, 82)) | ||
>V : Symbol(V, Decl(intersectionsOfLargeUnions.ts, 19, 41)) | ||
|
||
if (assertNodeTagName(node, tagName)) { | ||
>assertNodeTagName : Symbol(assertNodeTagName, Decl(intersectionsOfLargeUnions.ts, 5, 1)) | ||
>node : Symbol(node, Decl(intersectionsOfLargeUnions.ts, 20, 43)) | ||
>tagName : Symbol(tagName, Decl(intersectionsOfLargeUnions.ts, 20, 61)) | ||
|
||
node[prop]; | ||
>node : Symbol(node, Decl(intersectionsOfLargeUnions.ts, 20, 43)) | ||
>prop : Symbol(prop, Decl(intersectionsOfLargeUnions.ts, 20, 73)) | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possible optimization:
unionOfUnitTypes
should just beadditionalFlags
, and we should calculategetPropagatingFlagsOfTypes
piece-wise while doingincludes
, and just pass them in (rather then making another pass over the type here to calculate them).... although I know right now to save flag space we re-purpose the propagating flags during include calculation, which could make that.... hard.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, but I don't really want to mess with that now.