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

Discriminate contextual types #19733

Merged
merged 5 commits into from
Nov 7, 2017

Conversation

weswigham
Copy link
Member

@weswigham weswigham commented Nov 4, 2017

This was split from #19587, and the idea originated from a comment on #19322 (and then the code moved directly into getApparentTypeOfContextualType instead of getContextualThisParameterType so as to be more general), and should be merged after #19587. The primary baseline changes will be visible in tests added in that PR; however there are some small changes already visible here because we toss out uninteresting contextual types earlier based on members we know the type of.

This causes a few things:

  • Contextual this types are discriminated based on the other members you wrote; meaning methods in objects contextually typed by something now have the this type of only the discriminated member you've indicated, if possible. (This is the primary benefit the tests in the other PR can show)
  • Contextually typed object literal members are no longer contextually typed by elements of the union for which a discriminant infers they do not apply (for example, if a method signature would be typed by multiple signatures from various discriminant members before, now it will just be typed by one if a discriminant can successfully be applied) - I've added a test for this; this really improves our behavior here (given how badly we handle mismatched signatures).

Copy link
Member

@sandersn sandersn left a comment

Choose a reason for hiding this comment

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

This is a cool fix! A couple of requests:

return type && getApparentType(type);
let contextualType = getContextualType(node);
contextualType = contextualType && getApparentType(contextualType);
if (contextualType && contextualType.flags & TypeFlags.Union && isObjectLiteralExpression(node)) {
Copy link
Member

Choose a reason for hiding this comment

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

invert this I think

contextualType = contextualType && getApparentType(contextualType);
if (contextualType && contextualType.flags & TypeFlags.Union && isObjectLiteralExpression(node)) {
let match: Type | undefined;
propLoop: for (const prop of node.properties) {
Copy link
Member

@sandersn sandersn Nov 6, 2017

Choose a reason for hiding this comment

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

this code is almost exactly the same as the also-highly-questionable findMatchingDiscriminantType. The only real difference, I suspect, is that this code doesn't bail if (type === match). Two things:

  1. Can you harmonise the two code paths so there's only one findMatchingDiscriminantType?
    2.It's quite possible that the excess-property usage and union-error usage would both benefit from the (type === match) addition, so it could be that you can just swap out the existing body for this code.
  2. Three things! Using findMatchingDiscriminantType is slow, and only makes the compiler faster because it eliminates unions early on. Can you test performance with this change?

Copy link
Member Author

@weswigham weswigham Nov 6, 2017

Choose a reason for hiding this comment

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

  1. findMatchingDiscriminantType operates on type members (and findMatchingDiscriminantType directly uses isRelatedTo), this operates on an actual node tree (as most contextual type operations do), so sadly I don't think they can be merged (without a bunch of inefficient abstractions over weather you're getting symbols from types or nodes and such)
  2. Sure, I'll try modifying findMatchingDiscriminantType, too; but I don't think it'll show up in much unless we add a test case where multiple fields are capable of acting as a discriminant for an object and discriminate to the same types. 🐱
  3. Sure, will do.

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh hey, waddoyaknow, we already do have a test (excessPropertyCheckWithUnions) improved by changing findMatchingDiscriminantType. Neat.

@weswigham
Copy link
Member Author

weswigham commented Nov 6, 2017

@sandersn As far as overall perf goes, this has no real effect on any codebase in our perf suite:

Metric master discriminate-contextual-types Delta Best Worst
Compiler - Unions - node (v9.0.0, x64)
Memory used 202,235k (± 0.02%) 202,257k (± 0.01%) +22k (+ 0.01%) 202,214k 202,311k
Parse Time 0.67s (± 1.88%) 0.66s (± 0.61%) -0.00s (- 0.75%) 0.65s 0.67s
Bind Time 0.61s (± 2.03%) 0.60s (± 1.17%) -0.01s (- 1.96%) 0.59s 0.62s
Check Time 10.14s (± 1.07%) 10.09s (± 0.80%) -0.05s (- 0.49%) 9.89s 10.27s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 11.42s (± 0.98%) 11.35s (± 0.71%) -0.07s (- 0.60%) 11.15s 11.52s
Monaco - node (v9.0.0, x64)
Memory used 330,450k (± 0.01%) 330,510k (± 0.02%) +61k (+ 0.02%) 330,402k 330,684k
Parse Time 1.58s (± 2.84%) 1.55s (± 0.84%) -0.03s (- 1.77%) 1.52s 1.58s
Bind Time 0.70s (± 0.64%) 0.71s (± 0.82%) +0.01s (+ 1.29%) 0.70s 0.72s
Check Time 3.24s (± 0.44%) 3.24s (± 0.55%) +0.00s (+ 0.06%) 3.20s 3.29s
Emit Time 2.59s (± 0.70%) 2.58s (± 0.96%) -0.01s (- 0.31%) 2.52s 2.66s
Total Time 8.10s (± 0.77%) 8.08s (± 0.63%) -0.02s (- 0.28%) 7.99s 8.23s
TFS - node (v9.0.0, x64)
Memory used 287,749k (± 0.02%) 287,707k (± 0.02%) -43k (- 0.01%) 287,594k 287,820k
Parse Time 1.17s (± 1.66%) 1.17s (± 0.76%) -0.00s (- 0.09%) 1.15s 1.19s
Bind Time 0.52s (± 1.34%) 0.52s (± 1.13%) +0.00s (+ 0.58%) 0.51s 0.54s
Check Time 3.00s (± 1.24%) 3.01s (± 1.73%) +0.02s (+ 0.67%) 2.95s 3.18s
Emit Time 2.07s (± 0.74%) 2.07s (± 1.07%) -0.00s (- 0.00%) 2.02s 2.11s
Total Time 6.75s (± 0.69%) 6.77s (± 1.08%) +0.02s (+ 0.31%) 6.67s 6.99s

@weswigham weswigham merged commit d79c37c into microsoft:master Nov 7, 2017
@weswigham weswigham deleted the discriminate-contextual-types branch November 7, 2017 00:09
@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants