Skip to content

Port --traceResolutions #1537

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

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions internal/checker/checker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ foo.bar;`
fs = bundled.WrapFS(fs)

cd := "/"
host := compiler.NewCompilerHost(cd, fs, bundled.LibPath(), nil)
host := compiler.NewCompilerHost(cd, fs, bundled.LibPath(), nil, nil)

parsed, errors := tsoptions.GetParsedCommandLineOfConfigFile("/tsconfig.json", &core.CompilerOptions{}, host, nil)
assert.Equal(t, len(errors), 0, "Expected no errors in parsed command line")
Expand Down Expand Up @@ -70,7 +70,7 @@ func TestCheckSrcCompiler(t *testing.T) {

rootPath := tspath.CombinePaths(tspath.NormalizeSlashes(repo.TypeScriptSubmodulePath), "src", "compiler")

host := compiler.NewCompilerHost(rootPath, fs, bundled.LibPath(), nil)
host := compiler.NewCompilerHost(rootPath, fs, bundled.LibPath(), nil, nil)
parsed, errors := tsoptions.GetParsedCommandLineOfConfigFile(tspath.CombinePaths(rootPath, "tsconfig.json"), &core.CompilerOptions{}, host, nil)
assert.Equal(t, len(errors), 0, "Expected no errors in parsed command line")
p := compiler.NewProgram(compiler.ProgramOptions{
Expand All @@ -87,7 +87,7 @@ func BenchmarkNewChecker(b *testing.B) {

rootPath := tspath.CombinePaths(tspath.NormalizeSlashes(repo.TypeScriptSubmodulePath), "src", "compiler")

host := compiler.NewCompilerHost(rootPath, fs, bundled.LibPath(), nil)
host := compiler.NewCompilerHost(rootPath, fs, bundled.LibPath(), nil, nil)
parsed, errors := tsoptions.GetParsedCommandLineOfConfigFile(tspath.CombinePaths(rootPath, "tsconfig.json"), &core.CompilerOptions{}, host, nil)
assert.Equal(b, len(errors), 0, "Expected no errors in parsed command line")
p := compiler.NewProgram(compiler.ProgramOptions{
Expand Down
53 changes: 37 additions & 16 deletions internal/compiler/fileloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ import (
"github.com/microsoft/typescript-go/internal/tspath"
)

type libResolution struct {
libraryName string
resolution *module.ResolvedModule
trace []string
}

type fileLoader struct {
opts ProgramOptions
resolver *module.Resolver
Expand All @@ -35,7 +41,7 @@ type fileLoader struct {
dtsDirectories collections.Set[tspath.Path]

pathForLibFileCache collections.SyncMap[string, string]
pathForLibFileResolutions collections.SyncMap[tspath.Path, module.ModeAwareCache[*module.ResolvedModule]]
pathForLibFileResolutions collections.SyncMap[tspath.Path, *libResolution]
}

type processedFiles struct {
Expand Down Expand Up @@ -200,15 +206,20 @@ func processAllProgramFiles(
}
}

loader.pathForLibFileResolutions.Range(func(key tspath.Path, value module.ModeAwareCache[*module.ResolvedModule]) bool {
resolvedModules[key] = value
for _, resolvedModule := range value {
for _, diag := range resolvedModule.ResolutionDiagnostics {
fileLoadDiagnostics.Add(diag)
}
keys := slices.Collect(loader.pathForLibFileResolutions.Keys())
slices.Sort(keys)
for _, key := range keys {
value, _ := loader.pathForLibFileResolutions.Load(key)
resolvedModules[key] = module.ModeAwareCache[*module.ResolvedModule]{
module.ModeAwareCacheKey{Name: value.libraryName, Mode: core.ModuleKindCommonJS}: value.resolution,
}
return true
})
for _, trace := range value.trace {
opts.Host.Trace(trace)
}
for _, diag := range value.resolution.ResolutionDiagnostics {
fileLoadDiagnostics.Add(diag)
}
}

return processedFiles{
resolver: loader.resolver,
Expand Down Expand Up @@ -255,15 +266,17 @@ func (p *fileLoader) addAutomaticTypeDirectiveTasks() {
func (p *fileLoader) resolveAutomaticTypeDirectives(containingFileName string) (
toParse []resolvedRef,
typeResolutionsInFile module.ModeAwareCache[*module.ResolvedTypeReferenceDirective],
typeResolutionsTrace []string,
) {
automaticTypeDirectiveNames := module.GetAutomaticTypeDirectiveNames(p.opts.Config.CompilerOptions(), p.opts.Host)
if len(automaticTypeDirectiveNames) != 0 {
toParse = make([]resolvedRef, 0, len(automaticTypeDirectiveNames))
typeResolutionsInFile = make(module.ModeAwareCache[*module.ResolvedTypeReferenceDirective], len(automaticTypeDirectiveNames))
for _, name := range automaticTypeDirectiveNames {
resolutionMode := core.ModuleKindNodeNext
resolved := p.resolver.ResolveTypeReferenceDirective(name, containingFileName, resolutionMode, nil)
resolved, trace := p.resolver.ResolveTypeReferenceDirective(name, containingFileName, resolutionMode, nil)
typeResolutionsInFile[module.ModeAwareCacheKey{Name: name, Mode: resolutionMode}] = resolved
typeResolutionsTrace = append(typeResolutionsTrace, trace...)
if resolved.IsResolved() {
toParse = append(toParse, resolvedRef{
fileName: resolved.ResolvedFileName,
Expand All @@ -273,7 +286,7 @@ func (p *fileLoader) resolveAutomaticTypeDirectives(containingFileName string) (
}
}
}
return toParse, typeResolutionsInFile
return toParse, typeResolutionsInFile, typeResolutionsTrace
}

func (p *fileLoader) addProjectReferenceTasks(singleThreaded bool) {
Expand Down Expand Up @@ -393,11 +406,13 @@ func (p *fileLoader) resolveTypeReferenceDirectives(t *parseTask) {
meta := t.metadata

typeResolutionsInFile := make(module.ModeAwareCache[*module.ResolvedTypeReferenceDirective], len(file.TypeReferenceDirectives))
var typeResolutionsTrace []string
for _, ref := range file.TypeReferenceDirectives {
redirect := p.projectReferenceFileMapper.getRedirectForResolution(file)
resolutionMode := getModeForTypeReferenceDirectiveInFile(ref, file, meta, module.GetCompilerOptionsWithRedirect(p.opts.Config.CompilerOptions(), redirect))
resolved := p.resolver.ResolveTypeReferenceDirective(ref.FileName, file.FileName(), resolutionMode, redirect)
resolved, trace := p.resolver.ResolveTypeReferenceDirective(ref.FileName, file.FileName(), resolutionMode, redirect)
typeResolutionsInFile[module.ModeAwareCacheKey{Name: ref.FileName, Mode: resolutionMode}] = resolved
typeResolutionsTrace = append(typeResolutionsTrace, trace...)

if resolved.IsResolved() {
t.addSubTask(resolvedRef{
Expand All @@ -410,6 +425,7 @@ func (p *fileLoader) resolveTypeReferenceDirectives(t *parseTask) {
}

t.typeResolutionsInFile = typeResolutionsInFile
t.typeResolutionsTrace = typeResolutionsTrace
}

const externalHelpersModuleNameText = "tslib" // TODO(jakebailey): dedupe
Expand Down Expand Up @@ -455,6 +471,7 @@ func (p *fileLoader) resolveImportsAndModuleAugmentations(t *parseTask) {

if len(moduleNames) != 0 {
resolutionsInFile := make(module.ModeAwareCache[*module.ResolvedModule], len(moduleNames))
var resolutionsTrace []string

for index, entry := range moduleNames {
moduleName := entry.Text()
Expand All @@ -463,8 +480,9 @@ func (p *fileLoader) resolveImportsAndModuleAugmentations(t *parseTask) {
}

mode := getModeForUsageLocation(file.FileName(), meta, entry, optionsForFile)
resolvedModule := p.resolver.ResolveModuleName(moduleName, file.FileName(), mode, redirect)
resolvedModule, trace := p.resolver.ResolveModuleName(moduleName, file.FileName(), mode, redirect)
resolutionsInFile[module.ModeAwareCacheKey{Name: moduleName, Mode: mode}] = resolvedModule
resolutionsTrace = append(resolutionsTrace, trace...)

if !resolvedModule.IsResolved() {
continue
Expand Down Expand Up @@ -501,6 +519,7 @@ func (p *fileLoader) resolveImportsAndModuleAugmentations(t *parseTask) {
}

t.resolutionsInFile = resolutionsInFile
t.resolutionsTrace = resolutionsTrace
}
}

Expand All @@ -526,11 +545,13 @@ func (p *fileLoader) pathForLibFile(name string) string {
if p.opts.Config.CompilerOptions().LibReplacement.IsTrue() {
libraryName := getLibraryNameFromLibFileName(name)
resolveFrom := getInferredLibraryNameResolveFrom(p.opts.Config.CompilerOptions(), p.opts.Host.GetCurrentDirectory(), name)
resolution := p.resolver.ResolveModuleName(libraryName, resolveFrom, core.ModuleKindCommonJS, nil)
resolution, trace := p.resolver.ResolveModuleName(libraryName, resolveFrom, core.ModuleKindCommonJS, nil)
if resolution.IsResolved() {
path = resolution.ResolvedFileName
p.pathForLibFileResolutions.LoadOrStore(p.toPath(resolveFrom), module.ModeAwareCache[*module.ResolvedModule]{
module.ModeAwareCacheKey{Name: libraryName, Mode: core.ModuleKindCommonJS}: resolution,
p.pathForLibFileResolutions.LoadOrStore(p.toPath(resolveFrom), &libResolution{
libraryName: libraryName,
resolution: resolution,
trace: trace,
})
}
}
Expand Down
23 changes: 14 additions & 9 deletions internal/compiler/filesparser.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ type parseTask struct {

metadata ast.SourceFileMetaData
resolutionsInFile module.ModeAwareCache[*module.ResolvedModule]
resolutionsTrace []string
typeResolutionsInFile module.ModeAwareCache[*module.ResolvedTypeReferenceDirective]
typeResolutionsTrace []string
resolutionDiagnostics []*ast.Diagnostic
importHelpersImportSpecifier *ast.Node
jsxRuntimeImportSpecifier *jsxRuntimeImportSpecifier
Expand Down Expand Up @@ -98,8 +100,9 @@ func (t *parseTask) redirect(loader *fileLoader, fileName string) {
}

func (t *parseTask) loadAutomaticTypeDirectives(loader *fileLoader) {
toParseTypeRefs, typeResolutionsInFile := loader.resolveAutomaticTypeDirectives(t.normalizedFilePath)
toParseTypeRefs, typeResolutionsInFile, typeResolutionsTrace := loader.resolveAutomaticTypeDirectives(t.normalizedFilePath)
t.typeResolutionsInFile = typeResolutionsInFile
t.typeResolutionsTrace = typeResolutionsTrace
for _, typeResolution := range toParseTypeRefs {
t.addSubTask(typeResolution, false)
}
Expand Down Expand Up @@ -193,30 +196,32 @@ func (w *filesParser) start(loader *fileLoader, tasks []*parseTask, depth int, i
}
}

func (w *filesParser) collect(loader *fileLoader, tasks []*parseTask, iterate func(*parseTask)) []tspath.Path {
func (w *filesParser) collect(loader *fileLoader, tasks []*parseTask, iterate func(*parseTask)) {
// Mark all tasks we saw as external after the fact.
w.tasksByFileName.Range(func(key string, value *queuedParseTask) bool {
if value.fromExternalLibrary {
value.task.fromExternalLibrary = true
}
return true
})
return w.collectWorker(loader, tasks, iterate, collections.Set[*parseTask]{})
w.collectWorker(loader, tasks, iterate, collections.Set[*parseTask]{})
}

func (w *filesParser) collectWorker(loader *fileLoader, tasks []*parseTask, iterate func(*parseTask), seen collections.Set[*parseTask]) []tspath.Path {
var results []tspath.Path
func (w *filesParser) collectWorker(loader *fileLoader, tasks []*parseTask, iterate func(*parseTask), seen collections.Set[*parseTask]) {
for _, task := range tasks {
// ensure we only walk each task once
if !task.loaded || seen.Has(task) {
if !task.loaded || !seen.AddIfAbsent(task) {
continue
}
seen.Add(task)
for _, trace := range task.typeResolutionsTrace {
loader.opts.Host.Trace(trace)
}
for _, trace := range task.resolutionsTrace {
loader.opts.Host.Trace(trace)
}
if subTasks := task.subTasks; len(subTasks) > 0 {
w.collectWorker(loader, subTasks, iterate, seen)
}
iterate(task)
results = append(results, loader.toPath(task.FileName()))
}
return results
}
11 changes: 9 additions & 2 deletions internal/compiler/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,28 +30,35 @@ type compilerHost struct {
defaultLibraryPath string
extendedConfigCache *collections.SyncMap[tspath.Path, *tsoptions.ExtendedConfigCacheEntry]
extendedConfigCacheOnce sync.Once
trace func(msg string)
}

func NewCachedFSCompilerHost(
currentDirectory string,
fs vfs.FS,
defaultLibraryPath string,
extendedConfigCache *collections.SyncMap[tspath.Path, *tsoptions.ExtendedConfigCacheEntry],
trace func(msg string),
) CompilerHost {
return NewCompilerHost(currentDirectory, cachedvfs.From(fs), defaultLibraryPath, extendedConfigCache)
return NewCompilerHost(currentDirectory, cachedvfs.From(fs), defaultLibraryPath, extendedConfigCache, trace)
}

func NewCompilerHost(
currentDirectory string,
fs vfs.FS,
defaultLibraryPath string,
extendedConfigCache *collections.SyncMap[tspath.Path, *tsoptions.ExtendedConfigCacheEntry],
trace func(msg string),
) CompilerHost {
if trace == nil {
trace = func(msg string) {}
}
return &compilerHost{
currentDirectory: currentDirectory,
fs: fs,
defaultLibraryPath: defaultLibraryPath,
extendedConfigCache: extendedConfigCache,
trace: trace,
}
}

Expand All @@ -68,7 +75,7 @@ func (h *compilerHost) GetCurrentDirectory() string {
}

func (h *compilerHost) Trace(msg string) {
//!!! TODO: implement
h.trace(msg)
}

func (h *compilerHost) GetSourceFile(opts ast.SourceFileParseOptions) *ast.SourceFile {
Expand Down
19 changes: 10 additions & 9 deletions internal/compiler/program_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package compiler
package compiler_test

import (
"path/filepath"
Expand All @@ -7,6 +7,7 @@ import (
"testing"

"github.com/microsoft/typescript-go/internal/bundled"
"github.com/microsoft/typescript-go/internal/compiler"
"github.com/microsoft/typescript-go/internal/core"
"github.com/microsoft/typescript-go/internal/repo"
"github.com/microsoft/typescript-go/internal/tsoptions"
Expand Down Expand Up @@ -233,14 +234,14 @@ func TestProgram(t *testing.T) {

opts := core.CompilerOptions{Target: testCase.target}

program := NewProgram(ProgramOptions{
program := compiler.NewProgram(compiler.ProgramOptions{
Config: &tsoptions.ParsedCommandLine{
ParsedConfig: &core.ParsedOptions{
FileNames: []string{"c:/dev/src/index.ts"},
CompilerOptions: &opts,
},
},
Host: NewCompilerHost("c:/dev/src", fs, bundled.LibPath(), nil),
Host: compiler.NewCompilerHost("c:/dev/src", fs, bundled.LibPath(), nil, nil),
})

actualFiles := []string{}
Expand Down Expand Up @@ -270,18 +271,18 @@ func BenchmarkNewProgram(b *testing.B) {
}

opts := core.CompilerOptions{Target: testCase.target}
programOpts := ProgramOptions{
programOpts := compiler.ProgramOptions{
Config: &tsoptions.ParsedCommandLine{
ParsedConfig: &core.ParsedOptions{
FileNames: []string{"c:/dev/src/index.ts"},
CompilerOptions: &opts,
},
},
Host: NewCompilerHost("c:/dev/src", fs, bundled.LibPath(), nil),
Host: compiler.NewCompilerHost("c:/dev/src", fs, bundled.LibPath(), nil, nil),
}

for b.Loop() {
NewProgram(programOpts)
compiler.NewProgram(programOpts)
}
})
}
Expand All @@ -294,18 +295,18 @@ func BenchmarkNewProgram(b *testing.B) {
fs := osvfs.FS()
fs = bundled.WrapFS(fs)

host := NewCompilerHost(rootPath, fs, bundled.LibPath(), nil)
host := compiler.NewCompilerHost(rootPath, fs, bundled.LibPath(), nil, nil)

parsed, errors := tsoptions.GetParsedCommandLineOfConfigFile(tspath.CombinePaths(rootPath, "tsconfig.json"), nil, host, nil)
assert.Equal(b, len(errors), 0, "Expected no errors in parsed command line")

opts := ProgramOptions{
opts := compiler.ProgramOptions{
Config: parsed,
Host: host,
}

for b.Loop() {
NewProgram(opts)
compiler.NewProgram(opts)
}
})
}
5 changes: 0 additions & 5 deletions internal/compiler/projectreferencedtsfakinghost.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,6 @@ func (h *projectReferenceDtsFakingHost) GetCurrentDirectory() string {
return h.host.GetCurrentDirectory()
}

// Trace implements module.ResolutionHost.
func (h *projectReferenceDtsFakingHost) Trace(msg string) {
h.host.Trace(msg)
}

type projectReferenceDtsFakingVfs struct {
projectReferenceFileMapper *projectReferenceFileMapper
dtsDirectories collections.Set[tspath.Path]
Expand Down
10 changes: 8 additions & 2 deletions internal/execute/tsc.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,12 @@ func findConfigFile(searchPath string, fileExists func(string) bool, configName
return result
}

func getTraceFromSys(sys System) func(msg string) {
return func(msg string) {
fmt.Fprintln(sys.Writer(), msg)
}
}

func performIncrementalCompilation(
sys System,
config *tsoptions.ParsedCommandLine,
Expand All @@ -231,7 +237,7 @@ func performIncrementalCompilation(
configTime time.Duration,
testing bool,
) CommandLineResult {
host := compiler.NewCachedFSCompilerHost(sys.GetCurrentDirectory(), sys.FS(), sys.DefaultLibraryPath(), extendedConfigCache)
host := compiler.NewCachedFSCompilerHost(sys.GetCurrentDirectory(), sys.FS(), sys.DefaultLibraryPath(), extendedConfigCache, getTraceFromSys(sys))
buildInfoReadStart := sys.Now()
oldProgram := incremental.ReadBuildInfoProgram(config, incremental.NewBuildInfoReader(host))
buildInfoReadTime := sys.Now().Sub(buildInfoReadStart)
Expand Down Expand Up @@ -270,7 +276,7 @@ func performCompilation(
extendedConfigCache *collections.SyncMap[tspath.Path, *tsoptions.ExtendedConfigCacheEntry],
configTime time.Duration,
) CommandLineResult {
host := compiler.NewCachedFSCompilerHost(sys.GetCurrentDirectory(), sys.FS(), sys.DefaultLibraryPath(), extendedConfigCache)
host := compiler.NewCachedFSCompilerHost(sys.GetCurrentDirectory(), sys.FS(), sys.DefaultLibraryPath(), extendedConfigCache, getTraceFromSys(sys))
// todo: cache, statistics, tracing
parseStart := sys.Now()
program := compiler.NewProgram(compiler.ProgramOptions{
Expand Down
Loading
Loading