Skip to content

Cache one nodebuilder per emit resolver, make emit resolver emit context scoped - #64649

Open
Wesley Wigham (weswigham) wants to merge 11 commits into
microsoft:mainfrom
weswigham:fix-emitcontext-emitresolver-layers
Open

Wesley Wigham (weswigham) wants to merge 11 commits into
microsoft:mainfrom
weswigham:fix-emitcontext-emitresolver-layers

Conversation

@weswigham

Copy link
Copy Markdown
Member

Fixes #64625

Comment thread tsc/internal/checker/checker.go Outdated
Comment thread tsc/internal/checker/nodebuilderimpl.go Outdated

Copilot AI left a comment

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.

Note

Copilot was unable to run its full agentic suite in this review.

Copilot review overview

Review effort: Lite
Findings: 5 Medium severity

Open (5)
What changed in this PR

This PR refactors emit resolver creation to be EmitContext-aware, updates related interfaces, and adjusts transformer/checker call sites to use the new API while sharing resolver link state via Checker.

Changes:

  • Update GetEmitResolver APIs to accept an EmitContext and remove EmitContext parameters from EmitResolver node-construction methods.
  • Centralize resolver link stores on Checker (EmitResolverLinks) and adjust EmitResolver to use them.
  • Update transformers, compiler emit host, language service, and tests to pass/create an EmitContext when requesting an emit resolver.
File Description
tsc/​internal/​transformers/​tstransforms/​importelision_test.go Updates tests to create an EmitContext and pass it into GetEmitResolver.
tsc/​internal/​transformers/​declarations/​util.go Switches helper functions from DeclarationEmitHost to printer.EmitResolver for flag checks.
tsc/​internal/​transformers/​declarations/​transform.go Routes flag checks and type construction through tx.resolver (context-bound) and updates resolver method calls.
tsc/​internal/​printer/​emitresolver.go Changes EmitResolver interface to no longer take EmitContext for node construction methods.
tsc/​internal/​printer/​emithost.go Updates EmitHost.GetEmitResolver signature to require an EmitContext.
tsc/​internal/​ls/​findallreferences.go Creates an EmitContext when requesting an emit resolver for visibility checks.
tsc/​internal/​compiler/​emitter.go Passes emitContext into host.GetEmitResolver.
tsc/​internal/​compiler/​emitHost.go Reworks emit host to produce emit resolvers via a function taking EmitContext.
tsc/​internal/​checker/​symbolaccessibility.go Switches to getDiagnosticsEmitResolver() for diagnostics-layer checks.
tsc/​internal/​checker/​nodebuilderimpl.go Switches to getDiagnosticsEmitResolver() for helper visibility/undefined checks.
tsc/​internal/​checker/​exports.go Switches to getDiagnosticsEmitResolver() for implicit undefined check.
tsc/​internal/​checker/​emitresolver.go Makes EmitResolver context-bound, caches a node builder per resolver, and moves link stores to Checker.
tsc/​internal/​checker/​checker.go Adds EmitResolverLinks, introduces GetEmitResolver(emitContext), and renames cached resolver accessor to getDiagnosticsEmitResolver().

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment thread tsc/internal/checker/emitresolver.go
Comment thread tsc/internal/compiler/emitHost.go Outdated
Comment thread tsc/internal/compiler/emitHost.go Outdated
Comment thread tsc/internal/compiler/emitHost.go Outdated
var type_, initializer *ast.Node
if ast.IsPrimitiveLiteralValue(unwrapParenthesizedExpression(expression), true) {
initializer = tx.resolver.CreateLiteralConstValue(tx.EmitContext(), tx.EmitContext().ParseNode(assignment), tx.tracker)
initializer = tx.resolver.CreateLiteralConstValue(tx.EmitContext().ParseNode(assignment), tx.tracker)
Comment thread tsc/internal/compiler/emitHost.go Outdated
import (
"context"
"sync"
"weak"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this strictly required? This will lock us out of tinygo for sure...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

What, the weak map? Yeah, we don't wanna leak emit contexts - since those retain node factories which in turn retain nodes (unless explicitly cleared). The cache has to be weak - or we have to break the contract of emit hosts managing emit contexts and shove emit host knowledge into the emit context just to manage a cache, which is.... bad.

You could always not cache but then every caller needs to be mindful of the lifetime, rather than letting the GC handle it.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

GC's always been bad to us anyway, so I made ownership and freeing of emit contexts explicit now instead of having a cache - no more global cache, callers should either take one or create one for long duration tasks.

What this means in practice is that since we make one emitHost per thread per file, that emitHost now makes one EmitResolver during the course of emitting that file (shared for both declaration and js emit), which was made with one EmitContext used throughout the whole process. Since the same checker is used for multiple files, the resolver still needs to use the checker lock... but nothing else should need any threading stuff.

This branch has not been deployed

No deployments
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

Status: Not started

Development

Successfully merging this pull request may close these issues.

Declaration emit re-walks a package.json exports map for every declaration (module specifier cache not shared across node builders)

3 participants