Skip to content
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

Defer resolution of true and false branches in conditional types #31354

Merged
merged 7 commits into from May 14, 2019

Conversation

ahejlsberg
Copy link
Member

@ahejlsberg ahejlsberg commented May 11, 2019

This PR restores our previous behavior of deferring resolution of the true and false branches of conditional types. This fixes the performance regression we were seeing with statement completion in projects using styled-components (performance is now similar to 3.3).

Because resolution of the true and false branches is deferred, simplifications of conditional types of the form T extends xxx ? T : never and T extends xxx ? never : T only occur when the actual declarations of the conditional types are written with identical types in the T position and type never in the other position (i.e. simplification doesn't occur when conditional types only match the pattern following instantiation). This shouldn't matter in practice as the types we really care about, Exclude and Extract, follow the pattern. For example, #28748 is still fixed.

EDIT: Conditional type simplification now takes place in getSimplifiedType and we simplify to the same extent as before, so the above comment no longer applies.

Fixes #31302.
Fixes #31341.

@ahejlsberg
Copy link
Member Author

@typescript-bot test this

@typescript-bot
Copy link
Collaborator

typescript-bot commented May 11, 2019

Heya @ahejlsberg, I've started to run the extended test suite on this PR at bb9c5c9. You can monitor the build here. It should now contribute to this PR's status checks.

@ahejlsberg
Copy link
Member Author

@typescript-bot run dt

@typescript-bot
Copy link
Collaborator

typescript-bot commented May 11, 2019

Heya @ahejlsberg, I've started to run the parallelized Definitely Typed test suite on this PR at bb9c5c9. You can monitor the build here. It should now contribute to this PR's status checks.

@ahejlsberg
Copy link
Member Author

ahejlsberg commented May 11, 2019

There are definitely significantly fewer types being created when the true and false branches are deferred.

Compiling styled-components with current master:

Files:            28
Lines:         21723
Nodes:         60563
Identifiers:   19996
Symbols:      129415
Types:        132769
Memory used: 207569K
I/O read:      0.01s
I/O write:     0.00s
Parse time:    0.40s
Bind time:     0.17s
Check time:    8.36s
Emit time:     0.00s
Total time:    8.92s

Compiling styled-components with this PR:

Files:            28
Lines:         21723
Nodes:         60563
Identifiers:   19996
Symbols:      121459
Types:         87840
Memory used: 168256K
I/O read:      0.01s
I/O write:     0.00s
Parse time:    0.39s
Bind time:     0.17s
Check time:    6.21s
Emit time:     0.00s
Total time:    6.77s

Compiling styled-components with 3.3.4:

Files:            28
Lines:         21776
Nodes:         61201
Identifiers:   20271
Symbols:      102024
Types:         63544
Memory used: 120873K
I/O read:      0.01s
I/O write:     0.00s
Parse time:    0.36s
Bind time:     0.18s
Check time:    4.84s
Emit time:     0.00s
Total time:    5.39s

Compiling styled-components with 3.4.5:

Files:            28
Lines:         21776
Nodes:         61203
Identifiers:   20273
Symbols:      129627
Types:        151297
Memory used: 183032K
I/O read:      0.01s
I/O write:     0.00s
Parse time:    0.37s
Bind time:     0.22s
Check time:    8.15s
Emit time:     0.00s
Total time:    8.75s

@j-oliveras
Copy link
Contributor

Probably fixes #31341 too.

@weswigham
Copy link
Member

@ahejlsberg we should be able to defer the simplification to assignability checking, similar to indexed accesses, to keep the fixed use-cases functional.

@weswigham
Copy link
Member

@ahejlsberg #31374 is open with what I suggested - perf impact (compared to this PR as-is) in styled-components is either minimal or positive, and all the simplifications continue to work as they do in master.

@ahejlsberg
Copy link
Member Author

@typescript-bot test this

@typescript-bot
Copy link
Collaborator

typescript-bot commented May 13, 2019

Heya @ahejlsberg, I've started to run the extended test suite on this PR at 066e4b6. You can monitor the build here. It should now contribute to this PR's status checks.

@ahejlsberg
Copy link
Member Author

@typescript-bot run dt

@typescript-bot
Copy link
Collaborator

typescript-bot commented May 13, 2019

Heya @ahejlsberg, I've started to run the parallelized Definitely Typed test suite on this PR at 066e4b6. You can monitor the build here. It should now contribute to this PR's status checks.

Type 'keyof B' is not assignable to type '"valueOf"'.
Type 'string | number | symbol' is not assignable to type '"valueOf"'.
Type 'string' is not assignable to type '"valueOf"'.
Type 'string' is not assignable to type 'number | "toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "length" | "substr" | "valueOf" | keyof A'.
Copy link
Member

@weswigham weswigham May 13, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did keyof A expand into... itself? o.O

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the first keyof A, A is a substitution type. It then gets expanded into keyof (A & string) which becomes the union that ends in keyof A where A is the actual type variable. Not ideal, but neither was the prior error message.

@ahejlsberg ahejlsberg merged commit fb6ae38 into master May 14, 2019
@ahejlsberg ahejlsberg deleted the deferConditionalTypes branch May 14, 2019 00:17
@ahejlsberg ahejlsberg added this to the TypeScript 3.5.0 milestone May 14, 2019
return getSimplifiedType(trueType, writing);
}
else if (isIntersectionEmpty(checkType, extendsType)) { // Always false
return neverType;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why wasn't this just a Debug.fail?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because it can happen and is perfectly fine when it does. Or am I misunderstanding your question?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, the comment "Always false" here refers to when the condition of the conditional type is known to always be false. It doesn't imply that the if condition is always false.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants