Skip to content

Simplify mergeEmitNode #59613

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

Closed
wants to merge 2 commits into from

Conversation

jakebailey
Copy link
Member

@armanio123 and I noticed in #59332 that simply copying leadingComments/trailingComments and force overwriting (rather than concatenating) fixes the comment duplication problem from #59332.

Reading things further, it the function already force copies over the other node's information (flags, comment ranges, etc). Out of interest, I tried removing some of the other "complicated" merging operations and found that they also worked fine when just regular slices.

Maybe this extra simplification is valid?

@typescript-bot typescript-bot added Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug labels Aug 12, 2024
@jakebailey
Copy link
Member Author

@typescript-bot perf test this faster

@typescript-bot
Copy link
Collaborator

typescript-bot commented Aug 12, 2024

Starting jobs; this comment will be updated as builds start and complete.

Command Status Results
perf test this faster ✅ Started 👀 Results

Comment on lines -7521 to -7527
function mergeTokenSourceMapRanges(sourceRanges: (TextRange | undefined)[], destRanges: (TextRange | undefined)[]) {
if (!destRanges) destRanges = [];
for (const key in sourceRanges) {
destRanges[key] = sourceRanges[key];
}
return destRanges;
}
Copy link
Member Author

Choose a reason for hiding this comment

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

I read this function and it sort of scared me; what if the test has more elements than the source? Then I replaced it and nothing changed, so I kept going...

Copy link
Member

Choose a reason for hiding this comment

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

sourceRanges and destRanges are holey arrays, so length doesn't actually matter. It probably should just be a Map<number, TextRange>, to be honest.

@typescript-bot
Copy link
Collaborator

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

Here they are:

tsc

Comparison Report - baseline..pr
Metric baseline pr Delta Best Worst p-value
Compiler-Unions - node (v18.15.0, x64)
Errors 30 30 ~ ~ ~ p=1.000 n=6
Symbols 62,153 62,153 ~ ~ ~ p=1.000 n=6
Types 50,242 50,242 ~ ~ ~ p=1.000 n=6
Memory used 193,568k (± 0.94%) 192,465k (± 0.10%) ~ 192,309k 192,737k p=0.936 n=6
Parse Time 1.30s (± 1.02%) 1.31s (± 0.48%) ~ 1.30s 1.32s p=0.300 n=6
Bind Time 0.71s (± 0.57%) 0.71s ~ ~ ~ p=0.405 n=6
Check Time 9.53s (± 0.54%) 9.56s (± 0.19%) ~ 9.53s 9.58s p=0.258 n=6
Emit Time 2.74s (± 0.55%) 2.72s (± 0.61%) -0.02s (- 0.91%) 2.70s 2.74s p=0.033 n=6
Total Time 14.29s (± 0.33%) 14.30s (± 0.17%) ~ 14.27s 14.33s p=0.571 n=6
angular-1 - node (v18.15.0, x64)
Errors 7 7 ~ ~ ~ p=1.000 n=6
Symbols 945,757 945,757 ~ ~ ~ p=1.000 n=6
Types 410,045 410,045 ~ ~ ~ p=1.000 n=6
Memory used 1,222,521k (± 0.00%) 1,222,515k (± 0.00%) ~ 1,222,452k 1,222,588k p=0.810 n=6
Parse Time 7.97s (± 0.60%) 7.94s (± 0.45%) ~ 7.88s 7.96s p=0.375 n=6
Bind Time 2.23s (± 0.52%) 2.24s (± 0.37%) ~ 2.23s 2.25s p=1.000 n=6
Check Time 36.26s (± 0.43%) 36.31s (± 0.42%) ~ 36.08s 36.53s p=0.575 n=6
Emit Time 17.69s (± 1.04%) 17.83s (± 0.26%) ~ 17.77s 17.91s p=0.258 n=6
Total Time 64.15s (± 0.48%) 64.30s (± 0.15%) ~ 64.18s 64.47s p=0.810 n=6
mui-docs - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 2,491,074 2,491,074 ~ ~ ~ p=1.000 n=6
Types 1,013,347 1,013,347 ~ ~ ~ p=1.000 n=6
Memory used 2,498,042k (± 0.00%) 2,497,996k (± 0.00%) ~ 2,497,930k 2,498,063k p=0.378 n=6
Parse Time 9.24s (± 0.33%) 9.25s (± 0.31%) ~ 9.21s 9.28s p=0.806 n=6
Bind Time 2.18s (± 0.61%) 2.18s (± 0.54%) ~ 2.17s 2.20s p=0.737 n=6
Check Time 75.71s (± 0.47%) 76.05s (± 0.16%) +0.34s (+ 0.45%) 75.89s 76.24s p=0.045 n=6
Emit Time 0.28s (± 2.70%) 0.28s (± 2.70%) ~ 0.27s 0.29s p=1.000 n=6
Total Time 87.41s (± 0.40%) 87.77s (± 0.16%) +0.35s (+ 0.40%) 87.63s 87.98s p=0.045 n=6
self-build-src - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 1,229,708 1,229,701 -7 (- 0.00%) ~ ~ p=0.001 n=6
Types 264,083 264,082 -1 (- 0.00%) ~ ~ p=0.001 n=6
Memory used 2,349,747k (± 0.02%) 2,349,792k (± 0.03%) ~ 2,349,071k 2,350,665k p=0.936 n=6
Parse Time 4.99s (± 0.43%) 5.01s (± 0.94%) ~ 4.97s 5.09s p=0.688 n=6
Bind Time 1.88s (± 0.82%) 1.87s (± 1.14%) ~ 1.85s 1.90s p=0.465 n=6
Check Time 34.60s (± 0.32%) 34.60s (± 0.31%) ~ 34.48s 34.78s p=0.748 n=6
Emit Time 3.32s (± 1.63%) 3.35s (± 0.58%) ~ 3.32s 3.37s p=0.628 n=6
Total Time 44.83s (± 0.19%) 44.84s (± 0.22%) ~ 44.71s 45.00s p=0.689 n=6
self-build-src-public-api - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 1,229,708 1,229,701 -7 (- 0.00%) ~ ~ p=0.001 n=6
Types 264,083 264,082 -1 (- 0.00%) ~ ~ p=0.001 n=6
Memory used 2,424,503k (± 0.01%) 2,424,184k (± 0.02%) ~ 2,423,480k 2,424,775k p=0.298 n=6
Parse Time 5.13s (± 0.83%) 5.15s (± 0.69%) ~ 5.09s 5.18s p=0.470 n=6
Bind Time 1.68s (± 0.58%) 1.69s (± 0.69%) ~ 1.67s 1.70s p=0.109 n=6
Check Time 35.07s (± 0.24%) 35.14s (± 0.30%) ~ 35.00s 35.27s p=0.298 n=6
Emit Time 3.42s (± 2.87%) 3.39s (± 0.30%) ~ 3.37s 3.40s p=0.747 n=6
Total Time 45.30s (± 0.30%) 45.37s (± 0.21%) ~ 45.24s 45.49s p=0.575 n=6
self-compiler - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 256,830 256,823 -7 (- 0.00%) ~ ~ p=0.001 n=6
Types 105,580 105,579 -1 (- 0.00%) ~ ~ p=0.001 n=6
Memory used 429,068k (± 0.02%) 429,027k (± 0.01%) ~ 428,980k 429,056k p=0.936 n=6
Parse Time 3.36s (± 0.67%) 3.36s (± 1.09%) ~ 3.31s 3.41s p=0.870 n=6
Bind Time 1.30s (± 1.73%) 1.30s (± 1.36%) ~ 1.28s 1.32s p=0.869 n=6
Check Time 18.02s (± 0.31%) 17.99s (± 0.38%) ~ 17.85s 18.03s p=0.871 n=6
Emit Time 1.66s (± 1.50%) 1.66s (± 0.62%) ~ 1.65s 1.68s p=0.808 n=6
Total Time 24.33s (± 0.36%) 24.31s (± 0.43%) ~ 24.11s 24.37s p=0.746 n=6
ts-pre-modules - node (v18.15.0, x64)
Errors 35 35 ~ ~ ~ p=1.000 n=6
Symbols 225,018 225,018 ~ ~ ~ p=1.000 n=6
Types 94,245 94,245 ~ ~ ~ p=1.000 n=6
Memory used 370,245k (± 0.03%) 370,232k (± 0.03%) ~ 370,102k 370,360k p=0.936 n=6
Parse Time 3.45s (± 0.62%) 3.45s (± 0.65%) ~ 3.42s 3.48s p=0.808 n=6
Bind Time 1.91s (± 0.27%) 1.94s (± 0.27%) +0.02s (+ 1.22%) 1.93s 1.94s p=0.004 n=6
Check Time 19.39s (± 0.57%) 19.36s (± 0.27%) ~ 19.31s 19.46s p=0.520 n=6
Emit Time 0.00s 0.00s ~ ~ ~ p=1.000 n=6
Total Time 24.75s (± 0.45%) 24.75s (± 0.23%) ~ 24.68s 24.82s p=0.935 n=6
vscode - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 2,999,115 2,999,115 ~ ~ ~ p=1.000 n=6
Types 1,033,196 1,033,196 ~ ~ ~ p=1.000 n=6
Memory used 3,124,410k (± 0.00%) 3,124,415k (± 0.00%) ~ 3,124,319k 3,124,490k p=0.810 n=6
Parse Time 13.83s (± 0.36%) 13.83s (± 0.30%) ~ 13.76s 13.88s p=0.748 n=6
Bind Time 4.28s (± 0.18%) 4.28s (± 0.32%) ~ 4.26s 4.30s p=0.672 n=6
Check Time 79.53s (± 0.46%) 79.59s (± 0.43%) ~ 79.05s 80.07s p=0.936 n=6
Emit Time 20.43s (± 0.31%) 20.37s (± 0.31%) ~ 20.28s 20.44s p=0.108 n=6
Total Time 118.06s (± 0.25%) 118.06s (± 0.30%) ~ 117.44s 118.49s p=0.810 n=6
webpack - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 274,227 274,227 ~ ~ ~ p=1.000 n=6
Types 111,803 111,803 ~ ~ ~ p=1.000 n=6
Memory used 420,523k (± 0.02%) 420,635k (± 0.04%) ~ 420,488k 420,889k p=0.298 n=6
Parse Time 4.87s (± 0.58%) 4.89s (± 0.33%) ~ 4.87s 4.91s p=0.168 n=6
Bind Time 2.14s (± 1.21%) 2.14s (± 0.59%) ~ 2.12s 2.15s p=1.000 n=6
Check Time 21.19s (± 0.45%) 21.18s (± 0.52%) ~ 21.05s 21.30s p=0.936 n=6
Emit Time 0.00s 0.00s ~ ~ ~ p=1.000 n=6
Total Time 28.20s (± 0.42%) 28.21s (± 0.37%) ~ 28.06s 28.34s p=0.810 n=6
xstate-main - node (v18.15.0, x64)
Errors 0 0 ~ ~ ~ p=1.000 n=6
Symbols 540,779 540,779 ~ ~ ~ p=1.000 n=6
Types 177,884 177,884 ~ ~ ~ p=1.000 n=6
Memory used 483,253k (± 0.01%) 483,276k (± 0.01%) ~ 483,202k 483,324k p=0.198 n=6
Parse Time 3.39s (± 0.60%) 3.40s (± 0.66%) ~ 3.37s 3.43s p=0.687 n=6
Bind Time 1.25s (± 0.88%) 1.26s (± 0.41%) ~ 1.25s 1.26s p=0.247 n=6
Check Time 18.04s (± 0.29%) 18.03s (± 0.26%) ~ 17.97s 18.10s p=0.630 n=6
Emit Time 0.00s 0.00s ~ ~ ~ p=1.000 n=6
Total Time 22.69s (± 0.20%) 22.69s (± 0.23%) ~ 22.60s 22.75s p=1.000 n=6
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • Compiler-Unions - node (v18.15.0, x64)
  • angular-1 - node (v18.15.0, x64)
  • mui-docs - node (v18.15.0, x64)
  • self-build-src - node (v18.15.0, x64)
  • self-build-src-public-api - node (v18.15.0, x64)
  • self-compiler - node (v18.15.0, x64)
  • ts-pre-modules - node (v18.15.0, x64)
  • vscode - node (v18.15.0, x64)
  • webpack - node (v18.15.0, x64)
  • xstate-main - node (v18.15.0, x64)
Benchmark Name Iterations
Current pr 6
Baseline baseline 6

Developer Information:

Download Benchmarks

@rbuckton
Copy link
Member

A lot of the complexity in mergeEmitNode is an attempt to be defensive against someone creating a synthetic node, setting various emit related properties on it (via emitNode), and then calling setOriginalNode. We likely don't have good test coverage for this, so it's possible that this could break existing custom transformers somewhere.

Comment on lines -7521 to -7527
function mergeTokenSourceMapRanges(sourceRanges: (TextRange | undefined)[], destRanges: (TextRange | undefined)[]) {
if (!destRanges) destRanges = [];
for (const key in sourceRanges) {
destRanges[key] = sourceRanges[key];
}
return destRanges;
}
Copy link
Member

Choose a reason for hiding this comment

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

sourceRanges and destRanges are holey arrays, so length doesn't actually matter. It probably should just be a Map<number, TextRange>, to be honest.

@@ -7449,13 +7446,13 @@ function mergeEmitNode(sourceEmitNode: EmitNode, destEmitNode: EmitNode | undefi
// `leadingComments` are concatenated with any existing leading comments on the destination
if (leadingComments) {
// We use `.slice()` in case `destEmitNode.leadingComments` is pushed to later
destEmitNode.leadingComments = addRange(leadingComments.slice(), destEmitNode.leadingComments);
destEmitNode.leadingComments = leadingComments.slice();
Copy link
Member

Choose a reason for hiding this comment

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

I worry this results in a different inconsistency now. Before, we would attempt to merge the emit information for the old node into anything set on the new node prior to calling setOriginalNode. Now we will conditionally overwrite some properties but not others.

const oldNode = ...;
addSyntheticLeadingComment(oldNode, SyntaxKind.SingleLineCommentTrivia, "foo");

const newNode = ...;
addSyntheticLeadingComment(oldNode, SyntaxKind.SingleLineCommentTrivia, "bar");
addSyntheticTrailingComment(oldNode, SyntaxKind.SingleLineCommentTrivia, "baz");

setOriginalNode(newNode, oldNode);

// before
getSyntheticLeadingComments(newNode).length; // 2 (foo and bar)
getSyntheticTrailingComments(newNode).length; // 1 (baz)

// after
getSyntheticLeadingComments(newNode).length; // 1 (foo)
getSyntheticTrailingComments(newNode).length; // 1 (baz)

After this change we end up with oldNode's leading comments but newNodes trailing comments, which seems more confusing.

Copy link
Member Author

Choose a reason for hiding this comment

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

I certainly am not confident in this PR, but we do need something for #59332.

Copy link
Member

Choose a reason for hiding this comment

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

I originally considered using appendIfUnique to avoid duplicating but also to concatenate. Would you think that's a good fix?

@rbuckton
Copy link
Member

The issue that drove this PR is not so much an issue with mergeEmitNode but with the implementation in #59332. I don't think we should take this change.

@rbuckton
Copy link
Member

I found the actual underlying problem in #59332 in setTextRange() in checker.ts, per #59332 (comment). I'm working up a PR for it now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants