Skip to content

Excess property checks for discriminated unions #16363

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

Merged
merged 9 commits into from
Oct 6, 2017

Conversation

sandersn
Copy link
Member

@sandersn sandersn commented Jun 8, 2017

Excess property checks for discriminated unions. Uses findMatchingDiscriminant just like #14006 does, which improves error messages for discriminated unions.

Fixes #12745

sandersn added 2 commits June 8, 2017 11:01
This uses the same code as #14006, which improves error messages for
discriminated unions.
@mhegazy
Copy link
Contributor

mhegazy commented Jun 9, 2017

@ahejlsberg mind taking a look.

@DanielRosenwasser
Copy link
Member

Awesome! Thanks for looking into this 👍

// check excess properties against discriminant type only, not the entire union
return hasExcessProperties(source, discriminantType, reportErrors);
}
}
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure it's that simple. What if multiple types in the target have a matching discriminant? I think there's an implicit assumption in your code that each target constituent has a unique discriminant, which may not be the case.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is similar to the problem with #14006, which added findMatchingDiscriminantType, although there the aim was to improve an existing error, so it was still improvement to return one of multiple possible types with matching discriminants.

I think a fix here would be to make findMatchingDiscriminantType not return anything if multiple types match. However, I'm not sure what type shows this behaviour. Is it something like { tag: "A", x } | { tag: "A", y } ?

Copy link
Member Author

Choose a reason for hiding this comment

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

{ tag: "A", x } | { tag: "A", y } already works with the current PR:

type AAA = { tag: "A", x: number } | { tag: "A", y: string };
let aaa: AAA;
aaa = { tag: "A", x: 12 }; // ok
aaa = { tag: "A", y: "Hi" }; // ok
aaa = { tag: "A", x: 12, extra: "extra" } // error

So I'm not sure how to construct a non-unique discriminant example that fails.

Copy link
Member Author

@sandersn sandersn Jun 9, 2017

Choose a reason for hiding this comment

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

Never mind, I oversimplified the discriminated union. The second example with y does indeed fail, but only if the type is type AABC = { tag: "A", x: number } | { tag: "A", y: string } | { tag: "B", z: boolean } | { tag: "C" }

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed in latest commit.

@sandersn
Copy link
Member Author

@ahejlsberg I forgot about this in between vacations, but I think it's ready to go. Do you want to take another look?

Copy link
Member

@weswigham weswigham left a comment

Choose a reason for hiding this comment

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

Github says this can be squashed and merged, but it's lying - this needs to be merged with master and re-baselined to get .type and .symbol baselines.

I do like the improved errors this gives, though. It's nice.

@sandersn
Copy link
Member Author

sandersn commented Oct 5, 2017

Thanks for the warning @weswigham. Updated.

@sandersn
Copy link
Member Author

sandersn commented Oct 6, 2017

After re-reading the code, it looked kind of slow to me. So I ran a performance test. The complete results are below. In summary, compile time got faster for Angular and the compiler (Unions variant). It was also faster for TFS, but not more than the reported margin of error [1]. Compile time was about the same for Monaco. More speedup came from checking than elsewhere.

The only reason I can think of for check time getting faster is excess property checking find lots of new errors and causing isRelatedTo to bail much earlier than before.

Project Baseline Current Delta Best Worst
Angular - node (v8.1.2, x64)
Memory used 324,322k (± 0.01%) 324,346k (± 0.01%) +24k (+ 0.01%) 324,245k 324,427k
Parse Time 1.38s (± 0.43%) 1.37s (± 0.55%) 0.02s ( 1.12%) 1.35s 1.42s
Bind Time 0.61s (± 1.40%) 0.59s (± 0.82%) 0.01s ( 1.98%) 0.58s 0.62s
Check Time 3.38s (± 0.42%) 3.28s (± 0.29%) 0.10s ( 2.93%) 3.24s 3.33s
Emit Time 4.17s (± 0.53%) 4.09s (± 0.51%) 0.08s ( 1.92%) 4.02s 4.18s
Total Time 9.55s (± 0.38%) 9.34s (± 0.36%) 0.21s ( 2.17%) 9.26s 9.48s
Compiler - Unions - node (v8.1.2, x64)
Memory used 205,900k (± 0.06%) 205,779k (± 0.10%) 121k ( 0.06%) 204,698k 205,997k
Parse Time 0.55s (± 0.87%) 0.55s (± 0.65%) 0.00s ( 0.37%) 0.54s 0.56s
Bind Time 0.76s (± 1.73%) 0.74s (± 1.03%) 0.02s ( 2.95%) 0.73s 0.78s
Check Time 9.47s (± 0.49%) 9.27s (± 0.56%) 0.20s ( 2.10%) 9.14s 9.63s
Emit Time 0.00s (± 0.00%) 0.00s (± NaN%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 10.78s (± 0.48%) 10.56s (± 0.53%) 0.22s ( 2.07%) 10.42s 10.97s
Monaco - node (v8.1.2, x64)
Memory used 333,304k (± 0.01%) 333,466k (± 0.00%) +161k (+ 0.05%) 333,382k 333,514k
Parse Time 1.17s (± 1.31%) 1.17s (± 1.19%) 0.00s ( 0.13%) 1.13s 1.24s
Bind Time 0.61s (± 2.27%) 0.60s (± 2.49%) 0.01s ( 1.65%) 0.55s 0.63s
Check Time 3.18s (± 0.62%) 3.17s (± 0.37%) 0.01s ( 0.38%) 3.13s 3.21s
Emit Time 1.93s (± 0.65%) 1.92s (± 0.55%) 0.01s ( 0.34%) 1.89s 2.00s
Total Time 6.89s (± 0.47%) 6.86s (± 0.27%) 0.03s ( 0.42%) 6.78s 6.94s
TFS - node (v8.1.2, x64)
Memory used 296,690k (± 0.00%) 296,687k (± 0.00%) 2k ( 0.00%) 296,635k 296,742k
Parse Time 0.96s (± 5.27%) 0.92s (± 1.72%) 0.04s ( 3.82%) 0.90s 1.05s
Bind Time 0.60s (± 3.79%) 0.59s (± 1.08%) 0.01s ( 1.50%) 0.57s 0.62s
Check Time 2.81s (± 4.42%) 2.75s (± 0.98%) 0.06s ( 2.19%) 2.70s 2.88s
Emit Time 1.89s (± 5.10%) 1.83s (± 1.15%) 0.06s ( 3.21%) 1.78s 1.94s
Total Time 6.26s (± 4.43%) 6.09s (± 0.93%) 0.17s ( 2.72%) 5.99s 6.49s

[1] I'm not really sure what the margin of error is, though. Is it the first standard deviation or something? I'll have to ask @rbuckton when I see him.

@sandersn
Copy link
Member Author

sandersn commented Oct 6, 2017

@mhegazy and I think that the reason may be improved narrowing resulting from early failures from hasExcessProperties.

@sandersn sandersn merged commit afa4842 into master Oct 6, 2017
@sandersn sandersn deleted the excess-property-checks-for-discriminated-unions branch October 6, 2017 17:54
@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.

7 participants