Skip to content

Handle recursive type references up to a certain level of expansion in inference #38011

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

Conversation

weswigham
Copy link
Member

Fixes #37982, which regressed with #33678 which this modifies.

When #33678 moved inference of recursive type references into inferFromObjectTypesWorker, it implicitly forbade all nested inferences from nested recursive types of the same target. Eg, if you have a Recursive<string | Recursive<boolean>>, it prevented any inference from occurring on the inner reference. With this change to the circularity checking logic in inferFromObjectTypes (and expanded isDeeplyNestedType to handle expanding recursive type references), we can now make inferences multiple times as the reference expands (if it does), up to a limit. (Namely 5 expansions - the same limit we have in place in relationship checking).

@@ -18822,15 +18839,27 @@ namespace ts {
// its symbol with the instance side which would lead to false positives.
const isNonConstructorObject = target.flags & TypeFlags.Object &&
!(getObjectFlags(target) & ObjectFlags.Anonymous && target.symbol && target.symbol.flags & SymbolFlags.Class);
const symbolOrType = isNonConstructorObject ? isTupleType(target) ? target.target : target.symbol : undefined;
const symbolOrType = getObjectFlags(target) & ObjectFlags.Reference && (target as TypeReference).node ? getNormalizedType(target, /*writing*/ false) : isNonConstructorObject ? isTupleType(target) ? target.target : target.symbol : undefined;
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 line (and the bail without setting Circularity below) essentially "undoes" #33678 insofar as if I only made this change, #37982 would be fixed (as now we'd explore all recursive type references so long as their normalized forms aren't identical), however doing just that reintroduces the issue #33678 fixed, since in that case, we have something like type T = [A<NonNullable<T>>] which expands to [A<NonNullable<NonNullable<T>>>] and so on. As it expands, at no point are the types "identical" (notable future work: collapsing noop conditional types like repeated NonNullable!), in fact, all that's shared is that the type reference is sourced from the same .target and .node. So when it was eliminating the recursion based on .target alone. it was essentially saying "you can't infer to a 1-tuple while inferring to a 1-tuple, if that 1-tuple is marked as recursive" (which, while in line with how limited inference is for other symbol-based object types without #31633, is a regression in behavior for recursive type references), which, in turn, meant you couldn't infer to, say, the second Q reference of [Q<string>, [Q<boolean | number>]] if Q caused the containing tuples to be marked as potentially recursive!

All this to say: the change in behavior was a direct consequence of two things: #33678 limited recursive type reference inference, and recursive type references are made syntactically, so they way they are declared changes if they're marked as potentially recursive or not, resulting in the differences noted in #37982. So the bulk of this change is about improving #33678 to allow exploring multiple instances of the "same" recursive type reference, so that syntactic determination if the reference is possibly recursive or not cannot be observed (up to a limit).

@weswigham
Copy link
Member Author

weswigham commented Apr 16, 2020

@typescript-bot user test this
@typescript-bot run dt
@typescript-bot test this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Apr 16, 2020

Heya @weswigham, I've started to run the parallelized community code test suite on this PR at 73317dc. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Apr 16, 2020

Heya @weswigham, I've started to run the parallelized Definitely Typed test suite on this PR at 73317dc. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Apr 16, 2020

Heya @weswigham, I've started to run the extended test suite on this PR at 73317dc. You can monitor the build here.

@weswigham
Copy link
Member Author

@typescript-bot perf test this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Apr 16, 2020

Heya @weswigham, I've started to run the perf test suite on this PR at 73317dc. You can monitor the build here.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

The user suite test run you requested has finished and failed. I've opened a PR with the baseline diff from master.

@weswigham
Copy link
Member Author

RWC and user baselines look fine, just waiting for DT and perf to come back~

@typescript-bot
Copy link
Collaborator

@weswigham
The results of the perf run you requested are in!

Here they are:

Comparison Report - master..38011

Metric master 38011 Delta Best Worst
Angular - node (v10.16.3, x64)
Memory used 327,745k (± 0.03%) 327,175k (± 0.03%) -570k (- 0.17%) 327,013k 327,348k
Parse Time 1.64s (± 0.53%) 1.64s (± 0.54%) +0.00s (+ 0.06%) 1.62s 1.66s
Bind Time 0.89s (± 0.67%) 0.88s (± 0.74%) -0.01s (- 0.90%) 0.87s 0.89s
Check Time 4.76s (± 0.39%) 4.78s (± 0.73%) +0.02s (+ 0.38%) 4.69s 4.84s
Emit Time 5.36s (± 0.50%) 5.33s (± 0.70%) -0.03s (- 0.58%) 5.25s 5.43s
Total Time 12.66s (± 0.31%) 12.63s (± 0.48%) -0.03s (- 0.21%) 12.52s 12.77s
Monaco - node (v10.16.3, x64)
Memory used 327,093k (± 0.02%) 327,040k (± 0.02%) -54k (- 0.02%) 326,872k 327,171k
Parse Time 1.26s (± 0.39%) 1.26s (± 0.47%) -0.00s (- 0.08%) 1.25s 1.28s
Bind Time 0.77s (± 0.77%) 0.78s (± 0.61%) +0.00s (+ 0.39%) 0.77s 0.79s
Check Time 4.78s (± 0.31%) 4.78s (± 0.34%) +0.00s (+ 0.06%) 4.74s 4.83s
Emit Time 2.92s (± 0.50%) 2.93s (± 0.79%) +0.01s (+ 0.34%) 2.88s 2.97s
Total Time 9.73s (± 0.17%) 9.74s (± 0.34%) +0.01s (+ 0.13%) 9.67s 9.83s
TFS - node (v10.16.3, x64)
Memory used 292,027k (± 0.02%) 292,009k (± 0.02%) -17k (- 0.01%) 291,890k 292,210k
Parse Time 0.97s (± 0.70%) 0.96s (± 0.81%) -0.01s (- 0.52%) 0.94s 0.98s
Bind Time 0.75s (± 0.69%) 0.75s (± 0.89%) +0.00s (+ 0.53%) 0.74s 0.77s
Check Time 4.31s (± 0.57%) 4.33s (± 0.62%) +0.03s (+ 0.63%) 4.29s 4.40s
Emit Time 3.07s (± 0.64%) 3.06s (± 0.84%) -0.01s (- 0.23%) 3.00s 3.11s
Total Time 9.09s (± 0.37%) 9.11s (± 0.24%) +0.02s (+ 0.19%) 9.05s 9.15s
material-ui - node (v10.16.3, x64)
Memory used 450,560k (± 0.01%) 450,333k (± 0.01%) -227k (- 0.05%) 450,179k 450,449k
Parse Time 1.78s (± 0.55%) 1.78s (± 0.47%) -0.00s (- 0.17%) 1.76s 1.80s
Bind Time 0.69s (± 0.69%) 0.68s (± 1.11%) -0.00s (- 0.29%) 0.67s 0.71s
Check Time 12.70s (± 0.48%) 12.67s (± 0.56%) -0.03s (- 0.26%) 12.53s 12.85s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 15.17s (± 0.41%) 15.14s (± 0.48%) -0.04s (- 0.25%) 15.01s 15.33s
Angular - node (v12.1.0, x64)
Memory used 303,225k (± 0.03%) 302,739k (± 0.03%) -486k (- 0.16%) 302,528k 302,931k
Parse Time 1.59s (± 0.67%) 1.59s (± 0.60%) -0.01s (- 0.50%) 1.57s 1.60s
Bind Time 0.88s (± 0.78%) 0.87s (± 0.64%) -0.00s (- 0.46%) 0.86s 0.89s
Check Time 4.66s (± 0.32%) 4.66s (± 0.41%) -0.00s (- 0.04%) 4.63s 4.72s
Emit Time 5.52s (± 0.76%) 5.50s (± 0.59%) -0.02s (- 0.34%) 5.41s 5.55s
Total Time 12.65s (± 0.30%) 12.62s (± 0.34%) -0.03s (- 0.24%) 12.52s 12.73s
Monaco - node (v12.1.0, x64)
Memory used 307,051k (± 0.02%) 307,031k (± 0.02%) -20k (- 0.01%) 306,903k 307,124k
Parse Time 1.23s (± 0.91%) 1.22s (± 0.74%) -0.00s (- 0.33%) 1.21s 1.25s
Bind Time 0.75s (± 1.11%) 0.75s (± 0.49%) +0.00s (+ 0.00%) 0.74s 0.75s
Check Time 4.60s (± 0.44%) 4.60s (± 0.44%) -0.00s (- 0.04%) 4.55s 4.64s
Emit Time 2.98s (± 0.83%) 2.96s (± 0.56%) -0.02s (- 0.77%) 2.92s 3.00s
Total Time 9.55s (± 0.35%) 9.52s (± 0.23%) -0.03s (- 0.30%) 9.48s 9.56s
TFS - node (v12.1.0, x64)
Memory used 274,350k (± 0.03%) 274,339k (± 0.02%) -11k (- 0.00%) 274,230k 274,446k
Parse Time 0.95s (± 1.11%) 0.94s (± 0.92%) -0.01s (- 0.53%) 0.92s 0.96s
Bind Time 0.71s (± 0.83%) 0.71s (± 1.60%) -0.00s (- 0.28%) 0.70s 0.74s
Check Time 4.24s (± 0.69%) 4.23s (± 0.45%) -0.01s (- 0.24%) 4.20s 4.29s
Emit Time 3.11s (± 1.11%) 3.09s (± 0.57%) -0.02s (- 0.68%) 3.05s 3.13s
Total Time 9.02s (± 0.53%) 8.98s (± 0.40%) -0.04s (- 0.43%) 8.90s 9.07s
material-ui - node (v12.1.0, x64)
Memory used 427,975k (± 0.06%) 427,689k (± 0.06%) -286k (- 0.07%) 426,733k 427,937k
Parse Time 1.76s (± 0.37%) 1.76s (± 0.58%) +0.00s (+ 0.06%) 1.74s 1.78s
Bind Time 0.63s (± 0.93%) 0.64s (± 1.20%) +0.01s (+ 1.28%) 0.61s 0.65s
Check Time 11.33s (± 1.02%) 11.32s (± 0.64%) -0.01s (- 0.11%) 11.21s 11.49s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 13.71s (± 0.87%) 13.71s (± 0.51%) -0.01s (- 0.04%) 13.58s 13.89s
Angular - node (v8.9.0, x64)
Memory used 322,562k (± 0.02%) 322,080k (± 0.02%) -481k (- 0.15%) 321,963k 322,283k
Parse Time 2.12s (± 0.26%) 2.13s (± 0.59%) +0.00s (+ 0.19%) 2.10s 2.16s
Bind Time 0.92s (± 1.27%) 0.93s (± 0.91%) +0.01s (+ 0.87%) 0.91s 0.95s
Check Time 5.42s (± 1.70%) 5.35s (± 1.50%) -0.07s (- 1.31%) 5.22s 5.51s
Emit Time 6.30s (± 0.71%) 6.40s (± 2.05%) +0.10s (+ 1.60%) 6.04s 6.64s
Total Time 14.76s (± 0.52%) 14.80s (± 0.57%) +0.04s (+ 0.28%) 14.56s 14.97s
Monaco - node (v8.9.0, x64)
Memory used 325,535k (± 0.01%) 325,535k (± 0.01%) -0k (- 0.00%) 325,390k 325,609k
Parse Time 1.55s (± 0.36%) 1.55s (± 0.40%) -0.00s (- 0.06%) 1.54s 1.56s
Bind Time 0.90s (± 0.66%) 0.91s (± 1.32%) +0.01s (+ 0.66%) 0.89s 0.94s
Check Time 5.38s (± 0.55%) 5.35s (± 0.50%) -0.04s (- 0.65%) 5.27s 5.39s
Emit Time 3.52s (± 0.55%) 3.47s (± 0.97%) -0.06s (- 1.56%) 3.38s 3.52s
Total Time 11.36s (± 0.37%) 11.27s (± 0.35%) -0.09s (- 0.76%) 11.17s 11.33s
TFS - node (v8.9.0, x64)
Memory used 291,545k (± 0.01%) 291,527k (± 0.01%) -18k (- 0.01%) 291,436k 291,622k
Parse Time 1.26s (± 0.54%) 1.26s (± 0.56%) -0.01s (- 0.47%) 1.24s 1.27s
Bind Time 0.75s (± 0.77%) 0.75s (± 0.46%) -0.01s (- 0.80%) 0.74s 0.75s
Check Time 4.97s (± 1.41%) 4.95s (± 1.72%) -0.02s (- 0.48%) 4.83s 5.16s
Emit Time 3.29s (± 2.97%) 3.29s (± 2.36%) -0.00s (- 0.06%) 3.11s 3.39s
Total Time 10.28s (± 0.47%) 10.24s (± 0.33%) -0.04s (- 0.37%) 10.17s 10.32s
material-ui - node (v8.9.0, x64)
Memory used 453,093k (± 0.01%) 452,902k (± 0.01%) -191k (- 0.04%) 452,790k 453,007k
Parse Time 2.13s (± 0.78%) 2.11s (± 0.45%) -0.01s (- 0.61%) 2.09s 2.13s
Bind Time 0.81s (± 0.90%) 0.81s (± 0.71%) +0.00s (+ 0.25%) 0.80s 0.82s
Check Time 16.85s (± 1.04%) 16.78s (± 1.11%) -0.07s (- 0.43%) 16.32s 17.16s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 19.79s (± 0.84%) 19.70s (± 0.93%) -0.08s (- 0.42%) 19.26s 20.08s
Angular - node (v8.9.0, x86)
Memory used 185,695k (± 0.02%) 185,454k (± 0.02%) -241k (- 0.13%) 185,370k 185,564k
Parse Time 2.07s (± 0.28%) 2.06s (± 0.52%) -0.02s (- 0.82%) 2.04s 2.08s
Bind Time 1.07s (± 0.37%) 1.07s (± 0.77%) +0.01s (+ 0.47%) 1.06s 1.09s
Check Time 5.02s (± 0.60%) 5.02s (± 0.79%) +0.00s (+ 0.08%) 4.96s 5.14s
Emit Time 6.07s (± 0.41%) 6.06s (± 1.73%) -0.01s (- 0.18%) 5.80s 6.41s
Total Time 14.23s (± 0.28%) 14.21s (± 0.86%) -0.02s (- 0.12%) 13.93s 14.61s
Monaco - node (v8.9.0, x86)
Memory used 185,352k (± 0.02%) 185,392k (± 0.02%) +40k (+ 0.02%) 185,315k 185,452k
Parse Time 1.59s (± 0.33%) 1.61s (± 1.12%) +0.02s (+ 1.38%) 1.58s 1.67s
Bind Time 0.77s (± 0.78%) 0.77s (± 0.44%) +0.00s (+ 0.13%) 0.76s 0.77s
Check Time 5.43s (± 0.40%) 5.44s (± 0.51%) +0.01s (+ 0.13%) 5.39s 5.50s
Emit Time 2.90s (± 1.31%) 2.86s (± 0.59%) -0.04s (- 1.21%) 2.84s 2.92s
Total Time 10.69s (± 0.51%) 10.68s (± 0.42%) -0.01s (- 0.07%) 10.61s 10.82s
TFS - node (v8.9.0, x86)
Memory used 166,941k (± 0.02%) 166,940k (± 0.02%) -1k (- 0.00%) 166,866k 167,054k
Parse Time 1.29s (± 0.81%) 1.29s (± 0.73%) +0.00s (+ 0.08%) 1.28s 1.33s
Bind Time 0.72s (± 1.04%) 0.71s (± 0.56%) -0.01s (- 1.12%) 0.70s 0.72s
Check Time 4.66s (± 0.55%) 4.66s (± 0.43%) +0.00s (+ 0.11%) 4.63s 4.71s
Emit Time 3.04s (± 2.96%) 2.96s (± 0.65%) -0.08s (- 2.70%) 2.90s 3.00s
Total Time 9.71s (± 0.89%) 9.63s (± 0.35%) -0.08s (- 0.82%) 9.56s 9.70s
material-ui - node (v8.9.0, x86)
Memory used 256,581k (± 0.01%) 256,440k (± 0.01%) -141k (- 0.06%) 256,362k 256,516k
Parse Time 2.18s (± 0.53%) 2.19s (± 0.40%) +0.00s (+ 0.18%) 2.17s 2.21s
Bind Time 0.68s (± 1.00%) 0.69s (± 0.75%) +0.00s (+ 0.73%) 0.68s 0.70s
Check Time 15.32s (± 0.72%) 15.41s (± 0.69%) +0.10s (+ 0.65%) 15.18s 15.74s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 18.18s (± 0.63%) 18.29s (± 0.57%) +0.11s (+ 0.59%) 18.06s 18.59s
System
Machine Namets-ci-ubuntu
Platformlinux 4.4.0-166-generic
Architecturex64
Available Memory16 GB
Available Memory1 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v10.16.3, x64)
  • node (v12.1.0, x64)
  • node (v8.9.0, x64)
  • node (v8.9.0, x86)
Scenarios
  • Angular - node (v10.16.3, x64)
  • Angular - node (v12.1.0, x64)
  • Angular - node (v8.9.0, x64)
  • Angular - node (v8.9.0, x86)
  • Monaco - node (v10.16.3, x64)
  • Monaco - node (v12.1.0, x64)
  • Monaco - node (v8.9.0, x64)
  • Monaco - node (v8.9.0, x86)
  • TFS - node (v10.16.3, x64)
  • TFS - node (v12.1.0, x64)
  • TFS - node (v8.9.0, x64)
  • TFS - node (v8.9.0, x86)
  • material-ui - node (v10.16.3, x64)
  • material-ui - node (v12.1.0, x64)
  • material-ui - node (v8.9.0, x64)
  • material-ui - node (v8.9.0, x86)
Benchmark Name Iterations
Current 38011 10
Baseline master 10

@weswigham
Copy link
Member Author

Perf and DT both look good, too~

@sandersn sandersn assigned ahejlsberg and unassigned weswigham May 5, 2020
@sandersn sandersn added the For Milestone Bug PRs that fix a bug with a specific milestone label May 5, 2020
@weswigham
Copy link
Member Author

ping @ahejlsberg

Copy link
Member

@ahejlsberg ahejlsberg left a comment

Choose a reason for hiding this comment

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

Just a minor suggested change.

@weswigham weswigham merged commit a3ee09d into microsoft:master Jun 24, 2020
@weswigham weswigham deleted the recursive-type-reference-inference-mk2 branch June 24, 2020 21:25
cangSDARM added a commit to cangSDARM/TypeScript that referenced this pull request Jun 28, 2020
* upstream/master:
  LEGO: check in for master to temporary branch.
  Preserve newlines between try/catch/finally, if/else, do/while (microsoft#39280)
  not narrow static property without type annotation in constructor. (microsoft#39252)
  Switch to ES Map/Set internally (microsoft#33771)
  fix(38840): omit completions for a spread like argument in a function definition (microsoft#38897)
  fix(38785): include in NavigationBar child items from default exported functions (microsoft#38915)
  LEGO: check in for master to temporary branch.
  LEGO: check in for master to temporary branch.
  Avoid effect of element access expression (microsoft#39174)
  Update typescript-eslint to 3.4.1-alpha.1 (microsoft#39260)
  Handle 'keyof' for generic tuple types (microsoft#39218)
  Disable unsound T[K] rule in subtype relations (microsoft#39249)
  LEGO: check in for master to temporary branch.
  Upgrade typescript-eslint version (microsoft#39242)
  Handle recursive type references up to a certain level of expansion in inference (microsoft#38011)
  Do not consider binding patterns in contextual types for return type inference where all the signature type parameters have defaults (microsoft#39081)
  LEGO: check in for master to temporary branch.

# Conflicts:
#	src/compiler/program.ts
#	src/compiler/types.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Author: Team For Milestone Bug PRs that fix a bug with a specific milestone
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

[3.9.0 BUG] Recursive type infer behaves differently when passing type literal and passing type alias
4 participants