Skip to content
Draft
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
16 changes: 14 additions & 2 deletions tsc/internal/compiler/fileInclude.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"github.com/microsoft/TypeScript/tsc/internal/tspath"
)

type fileIncludeKind int
type fileIncludeKind uint8

const (
// References from file
Expand All @@ -28,8 +28,8 @@ const (

type FileIncludeReason struct {
kind fileIncludeKind
index int
isDefaultLib bool
index int
referencedFile *referencedFileData
automaticTypeDirective *automaticTypeDirectiveFileData
canonicalSourceFile tspath.PathKey
Expand All @@ -41,6 +41,18 @@ type referencedFileData struct {
synthetic *ast.Node
}

func newReferencedFileIncludeReason(kind fileIncludeKind, file tspath.PathKey, index int, synthetic *ast.Node) *FileIncludeReason {
r := &struct {
reason FileIncludeReason
data referencedFileData
}{
reason: FileIncludeReason{kind: kind},
data: referencedFileData{file: file, index: index, synthetic: synthetic},
}
r.reason.referencedFile = &r.data
return &r.reason
}

type referenceFileLocation struct {
file *ast.SourceFile
node *ast.Node
Expand Down
32 changes: 7 additions & 25 deletions tsc/internal/compiler/fileloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ func (p *fileLoader) addRootFileTask(fileName tspath.RootedFilePath, referenceTe
rootTask.normalizedFilePath = fileName
rootTask.path = p.caseSensitivity.PathKey(tspath.RootedPath(fileName))
rootTask.failedLookup = true
rootTask.parseTaskResult = &parseTaskResult{}
rootTask.processingDiagnostics = []*processingDiagnostic{{
kind: processingDiagnosticKindExplainingFileInclude,
explanation: &includeExplainingDiagnostic{
Expand Down Expand Up @@ -314,7 +315,7 @@ func (p *fileLoader) resolveAutomaticTypeDirectives(containingFileName tspath.Ro
kind: fileIncludeKindAutomaticTypeDirectiveFile,
automaticTypeDirective: &automaticTypeDirectiveFileData{name, resolved.PackageId},
},
packageId: resolved.PackageId,
packageId: packageIdRef(&resolved.PackageId),
})
} else {
pDiagnostics = append(pDiagnostics, &processingDiagnostic{
Expand Down Expand Up @@ -723,13 +724,7 @@ func (p *fileLoader) getSourceFileFromReference(
func (p *fileLoader) resolveTripleslashPathReference(moduleName string, containingFile tspath.RootedFilePath, index int) (*resolvedRef, *processingDiagnostic) {
normalizedFileName := containingFile.Directory().ResolveFile(moduleName)
containingPath := p.caseSensitivity.PathKey(tspath.RootedPath(containingFile))
includeReason := &FileIncludeReason{
kind: fileIncludeKindReferenceFile,
referencedFile: &referencedFileData{
file: containingPath,
index: index,
},
}
includeReason := newReferencedFileIncludeReason(fileIncludeKindReferenceFile, containingPath, index, nil)

resolvedFileName, resolvedPath, diagnostic := p.getSourceFileFromReference(
normalizedFileName,
Expand Down Expand Up @@ -783,13 +778,7 @@ func (p *fileLoader) resolveTypeReferenceDirectives(t *parseTask) {
traceDone = p.tracing.Push(tracing.PhaseProgram, "processTypeReferenceDirective", map[string]any{"directive": ref.FileName, "hasResolved": resolved.IsResolved(), "refKind": int(fileIncludeKindTypeReferenceDirective), "refPath": string(t.path)}, false)
}
typeResolutionsInFile[module.ModeAwareCacheKey{Name: ref.FileName, Mode: resolutionMode}] = resolved
includeReason := &FileIncludeReason{
kind: fileIncludeKindTypeReferenceDirective,
referencedFile: &referencedFileData{
file: t.path,
index: index,
},
}
includeReason := newReferencedFileIncludeReason(fileIncludeKindTypeReferenceDirective, t.path, index, nil)
typeResolutionsTrace = append(typeResolutionsTrace, trace...)

if resolved.IsResolved() {
Expand All @@ -799,7 +788,7 @@ func (p *fileLoader) resolveTypeReferenceDirectives(t *parseTask) {
increaseDepth: resolved.IsExternalLibraryImport,
elideOnDepth: false,
includeReason: includeReason,
packageId: resolved.PackageId,
packageId: packageIdRef(&resolved.PackageId),
}, nil)
} else {
t.processingDiagnostics = append(t.processingDiagnostics, &processingDiagnostic{
Expand Down Expand Up @@ -922,15 +911,8 @@ func (p *fileLoader) resolveImportsAndModuleAugmentations(t *parseTask) {
path: resolvedModule.ResolvedPath,
increaseDepth: resolvedModule.IsExternalLibraryImport,
elideOnDepth: isJsFileFromNodeModules,
includeReason: &FileIncludeReason{
kind: fileIncludeKindImport,
referencedFile: &referencedFileData{
file: t.path,
index: importIndex,
synthetic: core.IfElse(importIndex < 0, entry, nil),
},
},
packageId: resolvedModule.PackageId,
includeReason: newReferencedFileIncludeReason(fileIncludeKindImport, t.path, importIndex, core.IfElse(importIndex < 0, entry, nil)),
packageId: packageIdRef(&resolvedModule.PackageId),
}, nil)
}
}
Expand Down
45 changes: 27 additions & 18 deletions tsc/internal/compiler/filesparser.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,26 @@ type parseTask struct {
isContentMapperSupplemental bool
failedLookup bool
includeReason *FileIncludeReason
packageId module.PackageId
packageId *module.PackageId
increaseDepth bool
elideOnDepth bool
loadedTask *parseTask

// Most tasks are duplicate references to an already-loaded file, so
// state produced by loading lives in a separately allocated record that
// is only created when the task is loaded.
*parseTaskResult
}

type parseTaskResult struct {
metadata ast.SourceFileMetaData
resolutionsInFile module.ModeAwareCache[*module.ResolvedModule]
resolutionsTrace []module.DiagAndArgs
typeResolutionsInFile module.ModeAwareCache[*module.ResolvedTypeReferenceDirective]
typeResolutionsTrace []module.DiagAndArgs
resolutionDiagnostics []*ast.Diagnostic
processingDiagnostics []*processingDiagnostic
importHelpersImportSpecifier *ast.StringLiteralNode
jsxRuntimeImportSpecifier *jsxRuntimeImportSpecifier

increaseDepth bool
elideOnDepth bool

loadedTask *parseTask
allIncludeReasons []*FileIncludeReason
}

func (t *parseTask) FileName() tspath.RootedFilePath {
Expand All @@ -58,6 +61,9 @@ func (t *parseTask) PathKey() tspath.PathKey {

func (t *parseTask) load(loader *fileLoader) {
t.loaded = true
if t.parseTaskResult == nil {
t.parseTaskResult = &parseTaskResult{}
}
if t.isForAutomaticTypeDirective {
t.loadAutomaticTypeDirectives(loader)
return
Expand Down Expand Up @@ -146,13 +152,7 @@ func (t *parseTask) load(loader *fileLoader) {

if compilerOptions.NoLib != core.TSTrue && !loader.opts.SkipModuleResolution {
for index, lib := range file.LibReferenceDirectives {
includeReason := &FileIncludeReason{
kind: fileIncludeKindLibReferenceDirective,
referencedFile: &referencedFileData{
file: t.path,
index: index,
},
}
includeReason := newReferencedFileIncludeReason(fileIncludeKindLibReferenceDirective, t.path, index, nil)
if name, ok := tsoptions.GetLibFileName(lib.FileName); ok {
libFile := loader.pathForLibFile(name)
t.addSubTask(resolvedRef{
Expand Down Expand Up @@ -214,7 +214,16 @@ type resolvedRef struct {
increaseDepth bool
elideOnDepth bool
includeReason *FileIncludeReason
packageId module.PackageId
packageId *module.PackageId
}

// packageIdRef returns id, or nil if id is empty. Pointing into an existing
// resolution keeps the commonly empty ID out of every parse task.
func packageIdRef(id *module.PackageId) *module.PackageId {
if id.Name == "" {
return nil
}
return id
}

func (t *parseTask) addSubTask(ref resolvedRef, libFile *LibFile) {
Expand Down Expand Up @@ -297,8 +306,8 @@ func (w *filesParser) start(loader *fileLoader, tasks []*parseTask, depth int) {
}

// Propagate packageId to data if we have one and data doesn't yet
if data.packageId.Name == "" && task.packageId.Name != "" {
data.packageId = task.packageId
if data.packageId.Name == "" && task.packageId != nil {
data.packageId = *task.packageId
}

currentDepth := core.IfElse(task.increaseDepth, depth+1, depth)
Expand Down
4 changes: 1 addition & 3 deletions tsc/internal/core/workgroup.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ func (w *parallelWorkGroup) Queue(fn func()) {
panic("Queue called after RunAndWait returned")
}

w.wg.Go(func() {
fn()
})
w.wg.Go(fn)
}

func (w *parallelWorkGroup) RunAndWait() {
Expand Down
36 changes: 17 additions & 19 deletions tsc/internal/ls/autoimport/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,22 @@ const (
)

// ModuleID uniquely identifies either a file module or an ambient module.
// For file modules, value is a tspath.PathKey; for ambient modules, a tspath.ModuleSpecifier.
type ModuleID struct {
path tspath.PathKey
specifier tspath.ModuleSpecifier
kind moduleIDKind
value string
kind moduleIDKind
}

func fileModuleID(path tspath.PathKey) ModuleID {
return ModuleID{path: path, kind: moduleIDKindFile}
return ModuleID{value: string(path), kind: moduleIDKindFile}
}

func ambientModuleID(specifier string) ModuleID {
return ModuleID{specifier: tspath.ToModuleSpecifier(specifier), kind: moduleIDKindAmbient}
return ModuleID{value: string(tspath.ToModuleSpecifier(specifier)), kind: moduleIDKindAmbient}
}

func (m ModuleID) AsString() string {
switch m.kind {
case moduleIDKindFile:
return string(m.path)
case moduleIDKindAmbient:
return m.specifier.AsString()
default:
return ""
}
return m.value
}

func (m ModuleID) IsAmbient() bool {
Expand All @@ -52,22 +45,27 @@ func (m ModuleID) AsPathKey() (tspath.PathKey, bool) {
if m.kind != moduleIDKindFile {
return "", false
}
return m.path, true
return tspath.PathKeyFromCanonical(m.value), true
}

// IsFile reports whether m identifies the file module at path.
func (m ModuleID) IsFile(path tspath.PathKey) bool {
return m.kind == moduleIDKindFile && m.value == path.AsString()
}

func (m ModuleID) AsModuleSpecifier() (tspath.ModuleSpecifier, bool) {
if m.kind != moduleIDKindAmbient {
return "", false
}
return m.specifier, true
return tspath.ToModuleSpecifier(m.value), true
}

type ExportID struct {
ModuleID ModuleID
ExportName string
}

type ExportSyntax int
type ExportSyntax uint8

const (
ExportSyntaxNone ExportSyntax = iota
Expand Down Expand Up @@ -95,8 +93,8 @@ type Export struct {
ExportID
ModuleFileName tspath.RootedFilePath
UnresolvedModuleSpecifier tspath.ModuleSpecifier
Syntax ExportSyntax
Flags ast.SymbolFlags
Syntax ExportSyntax
localName string
// through is the name of the module symbol's export that this export was found on,
// either 'export=', InternalSymbolNameExportStar, or empty string.
Expand All @@ -105,9 +103,9 @@ type Export struct {
// Checker-set fields

Target ExportID
IsTypeOnly bool
ScriptElementKind lsutil.ScriptElementKind
ScriptElementKindModifiers lsutil.ScriptElementKindModifier
ScriptElementKind lsutil.ScriptElementKind
IsTypeOnly bool

// The file where the export was found.
Path tspath.PathKey
Expand Down
2 changes: 1 addition & 1 deletion tsc/internal/ls/autoimport/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func (v *View) search(searchFn func(*RegistryBucket) []*Export) []*Export {
exports := searchFn(bucket)
results = slices.Grow(results, len(exports))
for _, e := range exports {
if modulePath, ok := e.ModuleID.AsPathKey(); ok && modulePath == v.importingFile.PathKey() {
if e.ModuleID.IsFile(v.importingFile.PathKey()) {
// Don't auto-import from the importing file itself
continue
}
Expand Down
2 changes: 1 addition & 1 deletion tsc/internal/ls/lsutil/symbol_display.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"github.com/microsoft/TypeScript/tsc/internal/core"
)

type ScriptElementKind int
type ScriptElementKind uint8

const (
ScriptElementKindUnknown ScriptElementKind = iota
Expand Down
7 changes: 7 additions & 0 deletions tsc/internal/module/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ func resolutionCandidateFromDiskLogicalPath(directory tspath.RootedDirectoryPath
}

func resolutionCandidateFromEncodedPaths(directory tspath.RootedDirectoryPath, filePath string, directoryPath string, directoryOnly bool) resolutionCandidate {
if filePath == directoryPath {
// File and directory resolution of the same input are identical.
return resolutionCandidate{
path: directory.ResolveFile(filePath).AsPath(),
directoryOnly: directoryOnly,
}
}
resolvedDirectoryPath := directory.ResolveDirectory(directoryPath)
if directoryOnly {
return resolutionCandidate{
Expand Down
Loading
Loading