Skip to content

Simplify mergeEmitNode - #59613

Closed
Jake Bailey (jakebailey) wants to merge 2 commits into
microsoft:mainfrom
jakebailey:simplify-mergeEmitNode
Closed

Simplify mergeEmitNode#59613
Jake Bailey (jakebailey) wants to merge 2 commits into
microsoft:mainfrom
jakebailey:simplify-mergeEmitNode

Conversation

@jakebailey

Copy link
Copy Markdown
Member

Armando Aguirre (@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?

@jakebailey

Copy link
Copy Markdown
MemberAuthor

TypeScript Bot (@typescript-bot) perf test this faster

@typescript-bot

TypeScript Bot (typescript-bot) commented Aug 12, 2024

Copy link
Copy Markdown
Contributor

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

CommandStatusResults
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
Copy Markdown
MemberAuthor

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
Copy Markdown
Contributor

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
Copy Markdown
Contributor

Jake Bailey (@jakebailey)
The results of the perf run you requested are in!

Here they are:

tsc

Comparison Report - baseline..pr
MetricbaselineprDeltaBestWorstp-value
Compiler-Unions - node (v18.15.0, x64)
Errors3030~~~p=1.000 n=6
Symbols62,15362,153~~~p=1.000 n=6
Types50,24250,242~~~p=1.000 n=6
Memory used193,568k (± 0.94%)192,465k (± 0.10%)~192,309k192,737kp=0.936 n=6
Parse Time1.30s (± 1.02%)1.31s (± 0.48%)~1.30s1.32sp=0.300 n=6
Bind Time0.71s (± 0.57%)0.71s~~~p=0.405 n=6
Check Time9.53s (± 0.54%)9.56s (± 0.19%)~9.53s9.58sp=0.258 n=6
Emit Time2.74s (± 0.55%)2.72s (± 0.61%)-0.02s (- 0.91%)2.70s2.74sp=0.033 n=6
Total Time14.29s (± 0.33%)14.30s (± 0.17%)~14.27s14.33sp=0.571 n=6
angular-1 - node (v18.15.0, x64)
Errors77~~~p=1.000 n=6
Symbols945,757945,757~~~p=1.000 n=6
Types410,045410,045~~~p=1.000 n=6
Memory used1,222,521k (± 0.00%)1,222,515k (± 0.00%)~1,222,452k1,222,588kp=0.810 n=6
Parse Time7.97s (± 0.60%)7.94s (± 0.45%)~7.88s7.96sp=0.375 n=6
Bind Time2.23s (± 0.52%)2.24s (± 0.37%)~2.23s2.25sp=1.000 n=6
Check Time36.26s (± 0.43%)36.31s (± 0.42%)~36.08s36.53sp=0.575 n=6
Emit Time17.69s (± 1.04%)17.83s (± 0.26%)~17.77s17.91sp=0.258 n=6
Total Time64.15s (± 0.48%)64.30s (± 0.15%)~64.18s64.47sp=0.810 n=6
mui-docs - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols2,491,0742,491,074~~~p=1.000 n=6
Types1,013,3471,013,347~~~p=1.000 n=6
Memory used2,498,042k (± 0.00%)2,497,996k (± 0.00%)~2,497,930k2,498,063kp=0.378 n=6
Parse Time9.24s (± 0.33%)9.25s (± 0.31%)~9.21s9.28sp=0.806 n=6
Bind Time2.18s (± 0.61%)2.18s (± 0.54%)~2.17s2.20sp=0.737 n=6
Check Time75.71s (± 0.47%)76.05s (± 0.16%)+0.34s (+ 0.45%)75.89s76.24sp=0.045 n=6
Emit Time0.28s (± 2.70%)0.28s (± 2.70%)~0.27s0.29sp=1.000 n=6
Total Time87.41s (± 0.40%)87.77s (± 0.16%)+0.35s (+ 0.40%)87.63s87.98sp=0.045 n=6
self-build-src - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols1,229,7081,229,701-7 (- 0.00%)~~p=0.001 n=6
Types264,083264,082-1 (- 0.00%)~~p=0.001 n=6
Memory used2,349,747k (± 0.02%)2,349,792k (± 0.03%)~2,349,071k2,350,665kp=0.936 n=6
Parse Time4.99s (± 0.43%)5.01s (± 0.94%)~4.97s5.09sp=0.688 n=6
Bind Time1.88s (± 0.82%)1.87s (± 1.14%)~1.85s1.90sp=0.465 n=6
Check Time34.60s (± 0.32%)34.60s (± 0.31%)~34.48s34.78sp=0.748 n=6
Emit Time3.32s (± 1.63%)3.35s (± 0.58%)~3.32s3.37sp=0.628 n=6
Total Time44.83s (± 0.19%)44.84s (± 0.22%)~44.71s45.00sp=0.689 n=6
self-build-src-public-api - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols1,229,7081,229,701-7 (- 0.00%)~~p=0.001 n=6
Types264,083264,082-1 (- 0.00%)~~p=0.001 n=6
Memory used2,424,503k (± 0.01%)2,424,184k (± 0.02%)~2,423,480k2,424,775kp=0.298 n=6
Parse Time5.13s (± 0.83%)5.15s (± 0.69%)~5.09s5.18sp=0.470 n=6
Bind Time1.68s (± 0.58%)1.69s (± 0.69%)~1.67s1.70sp=0.109 n=6
Check Time35.07s (± 0.24%)35.14s (± 0.30%)~35.00s35.27sp=0.298 n=6
Emit Time3.42s (± 2.87%)3.39s (± 0.30%)~3.37s3.40sp=0.747 n=6
Total Time45.30s (± 0.30%)45.37s (± 0.21%)~45.24s45.49sp=0.575 n=6
self-compiler - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols256,830256,823-7 (- 0.00%)~~p=0.001 n=6
Types105,580105,579-1 (- 0.00%)~~p=0.001 n=6
Memory used429,068k (± 0.02%)429,027k (± 0.01%)~428,980k429,056kp=0.936 n=6
Parse Time3.36s (± 0.67%)3.36s (± 1.09%)~3.31s3.41sp=0.870 n=6
Bind Time1.30s (± 1.73%)1.30s (± 1.36%)~1.28s1.32sp=0.869 n=6
Check Time18.02s (± 0.31%)17.99s (± 0.38%)~17.85s18.03sp=0.871 n=6
Emit Time1.66s (± 1.50%)1.66s (± 0.62%)~1.65s1.68sp=0.808 n=6
Total Time24.33s (± 0.36%)24.31s (± 0.43%)~24.11s24.37sp=0.746 n=6
ts-pre-modules - node (v18.15.0, x64)
Errors3535~~~p=1.000 n=6
Symbols225,018225,018~~~p=1.000 n=6
Types94,24594,245~~~p=1.000 n=6
Memory used370,245k (± 0.03%)370,232k (± 0.03%)~370,102k370,360kp=0.936 n=6
Parse Time3.45s (± 0.62%)3.45s (± 0.65%)~3.42s3.48sp=0.808 n=6
Bind Time1.91s (± 0.27%)1.94s (± 0.27%)+0.02s (+ 1.22%)1.93s1.94sp=0.004 n=6
Check Time19.39s (± 0.57%)19.36s (± 0.27%)~19.31s19.46sp=0.520 n=6
Emit Time0.00s0.00s~~~p=1.000 n=6
Total Time24.75s (± 0.45%)24.75s (± 0.23%)~24.68s24.82sp=0.935 n=6
vscode - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols2,999,1152,999,115~~~p=1.000 n=6
Types1,033,1961,033,196~~~p=1.000 n=6
Memory used3,124,410k (± 0.00%)3,124,415k (± 0.00%)~3,124,319k3,124,490kp=0.810 n=6
Parse Time13.83s (± 0.36%)13.83s (± 0.30%)~13.76s13.88sp=0.748 n=6
Bind Time4.28s (± 0.18%)4.28s (± 0.32%)~4.26s4.30sp=0.672 n=6
Check Time79.53s (± 0.46%)79.59s (± 0.43%)~79.05s80.07sp=0.936 n=6
Emit Time20.43s (± 0.31%)20.37s (± 0.31%)~20.28s20.44sp=0.108 n=6
Total Time118.06s (± 0.25%)118.06s (± 0.30%)~117.44s118.49sp=0.810 n=6
webpack - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols274,227274,227~~~p=1.000 n=6
Types111,803111,803~~~p=1.000 n=6
Memory used420,523k (± 0.02%)420,635k (± 0.04%)~420,488k420,889kp=0.298 n=6
Parse Time4.87s (± 0.58%)4.89s (± 0.33%)~4.87s4.91sp=0.168 n=6
Bind Time2.14s (± 1.21%)2.14s (± 0.59%)~2.12s2.15sp=1.000 n=6
Check Time21.19s (± 0.45%)21.18s (± 0.52%)~21.05s21.30sp=0.936 n=6
Emit Time0.00s0.00s~~~p=1.000 n=6
Total Time28.20s (± 0.42%)28.21s (± 0.37%)~28.06s28.34sp=0.810 n=6
xstate-main - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols540,779540,779~~~p=1.000 n=6
Types177,884177,884~~~p=1.000 n=6
Memory used483,253k (± 0.01%)483,276k (± 0.01%)~483,202k483,324kp=0.198 n=6
Parse Time3.39s (± 0.60%)3.40s (± 0.66%)~3.37s3.43sp=0.687 n=6
Bind Time1.25s (± 0.88%)1.26s (± 0.41%)~1.25s1.26sp=0.247 n=6
Check Time18.04s (± 0.29%)18.03s (± 0.26%)~17.97s18.10sp=0.630 n=6
Emit Time0.00s0.00s~~~p=1.000 n=6
Total Time22.69s (± 0.20%)22.69s (± 0.23%)~22.60s22.75sp=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)
BenchmarkNameIterations
Currentpr6
Baselinebaseline6

Developer Information:

Download Benchmarks

@rbuckton

Copy link
Copy Markdown
Contributor

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
Copy Markdown
Contributor

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.

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
Copy Markdown
Contributor

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.

constoldNode= ...;addSyntheticLeadingComment(oldNode,SyntaxKind.SingleLineCommentTrivia,"foo");constnewNode= ...;addSyntheticLeadingComment(oldNode,SyntaxKind.SingleLineCommentTrivia,"bar");addSyntheticTrailingComment(oldNode,SyntaxKind.SingleLineCommentTrivia,"baz");setOriginalNode(newNode,oldNode);// beforegetSyntheticLeadingComments(newNode).length;// 2 (foo and bar)getSyntheticTrailingComments(newNode).length;// 1 (baz)// aftergetSyntheticLeadingComments(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
Copy Markdown
MemberAuthor

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
Copy Markdown
Contributor

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
Copy Markdown
Contributor

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
Copy Markdown
Contributor

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 freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Author: TeamFor Uncommitted BugPR for untriaged, rejected, closed or missing bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@jakebailey@typescript-bot@rbuckton@armanio123@sandersn