Skip to content

Commit b7b4fe2

Browse files
chore(sync): mirror internal packages into pkg/ (auto) (#17)
Co-authored-by: buke <1013738+buke@users.noreply.github.com>
1 parent d4febca commit b7b4fe2

35 files changed

+571
-139
lines changed

pkg/checker/checker.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30518,7 +30518,7 @@ func (c *Checker) getSymbolAtLocation(node *ast.Node, ignoreErrors bool) *ast.Sy
3051830518
}
3051930519
return nil
3052030520
case ast.KindDefaultKeyword, ast.KindFunctionKeyword, ast.KindEqualsGreaterThanToken, ast.KindClassKeyword:
30521-
return c.getSymbolOfNode(node)
30521+
return c.getSymbolOfNode(node.Parent)
3052230522
case ast.KindImportType:
3052330523
if ast.IsLiteralImportTypeNode(node) {
3052430524
return c.getSymbolAtLocation(node.AsImportTypeNode().Argument.AsLiteralTypeNode().Literal, ignoreErrors)

pkg/checker/nodebuilderimpl.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,9 @@ func (b *NodeBuilderImpl) getNameOfSymbolAsWritten(symbol *ast.Symbol) string {
886886
if len(name) > 0 {
887887
return name
888888
}
889+
if symbol.Name == ast.InternalSymbolNameMissing {
890+
return "__missing"
891+
}
889892
return symbol.Name
890893
}
891894

pkg/compiler/checkerpool.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ import (
1212
)
1313

1414
type CheckerPool interface {
15+
Count() int
1516
GetChecker(ctx context.Context) (*checker.Checker, func())
1617
GetCheckerForFile(ctx context.Context, file *ast.SourceFile) (*checker.Checker, func())
1718
GetCheckerForFileExclusive(ctx context.Context, file *ast.SourceFile) (*checker.Checker, func())
18-
GetAllCheckers(ctx context.Context) ([]*checker.Checker, func())
19+
ForEachCheckerParallel(ctx context.Context, cb func(idx int, c *checker.Checker))
1920
Files(checker *checker.Checker) iter.Seq[*ast.SourceFile]
2021
}
2122

@@ -42,6 +43,10 @@ func newCheckerPool(checkerCount int, program *Program) *checkerPool {
4243
return pool
4344
}
4445

46+
func (p *checkerPool) Count() int {
47+
return p.checkerCount
48+
}
49+
4550
func (p *checkerPool) GetCheckerForFile(ctx context.Context, file *ast.SourceFile) (*checker.Checker, func()) {
4651
p.createCheckers()
4752
checker := p.fileAssociations[file]
@@ -82,9 +87,19 @@ func (p *checkerPool) createCheckers() {
8287
})
8388
}
8489

85-
func (p *checkerPool) GetAllCheckers(ctx context.Context) ([]*checker.Checker, func()) {
90+
// Runs `cb` for each checker in the pool concurrently, locking and unlocking checker mutexes as it goes,
91+
// making it safe to call `ForEachCheckerParallel` from many threads simultaneously.
92+
func (p *checkerPool) ForEachCheckerParallel(ctx context.Context, cb func(idx int, c *checker.Checker)) {
8693
p.createCheckers()
87-
return p.checkers, noop
94+
wg := core.NewWorkGroup(p.program.SingleThreaded())
95+
for idx, checker := range p.checkers {
96+
wg.Queue(func() {
97+
p.locks[idx].Lock()
98+
defer p.locks[idx].Unlock()
99+
cb(idx, checker)
100+
})
101+
}
102+
wg.RunAndWait()
88103
}
89104

90105
func (p *checkerPool) Files(checker *checker.Checker) iter.Seq[*ast.SourceFile] {

pkg/compiler/program.go

Lines changed: 43 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"slices"
99
"strings"
1010
"sync"
11+
"sync/atomic"
1112

1213
"github.com/go-json-experiment/json"
1314
"github.com/buke/typescript-go-internal/pkg/ast"
@@ -351,28 +352,22 @@ func (p *Program) BindSourceFiles() {
351352
}
352353

353354
func (p *Program) CheckSourceFiles(ctx context.Context, files []*ast.SourceFile) {
354-
wg := core.NewWorkGroup(p.SingleThreaded())
355-
checkers, done := p.checkerPool.GetAllCheckers(ctx)
356-
defer done()
357-
for _, checker := range checkers {
358-
wg.Queue(func() {
359-
for file := range p.checkerPool.Files(checker) {
360-
if files == nil || slices.Contains(files, file) {
361-
checker.CheckSourceFile(ctx, file)
362-
}
355+
p.checkerPool.ForEachCheckerParallel(ctx, func(_ int, checker *checker.Checker) {
356+
for file := range p.checkerPool.Files(checker) {
357+
if files == nil || slices.Contains(files, file) {
358+
checker.CheckSourceFile(ctx, file)
363359
}
364-
})
365-
}
366-
wg.RunAndWait()
360+
}
361+
})
367362
}
368363

369364
// Return the type checker associated with the program.
370365
func (p *Program) GetTypeChecker(ctx context.Context) (*checker.Checker, func()) {
371366
return p.checkerPool.GetChecker(ctx)
372367
}
373368

374-
func (p *Program) GetTypeCheckers(ctx context.Context) ([]*checker.Checker, func()) {
375-
return p.checkerPool.GetAllCheckers(ctx)
369+
func (p *Program) ForEachCheckerParallel(ctx context.Context, cb func(idx int, c *checker.Checker)) {
370+
p.checkerPool.ForEachCheckerParallel(ctx, cb)
376371
}
377372

378373
// Return a checker for the given file. We may have multiple checkers in concurrent scenarios and this
@@ -965,14 +960,12 @@ func (p *Program) GetGlobalDiagnostics(ctx context.Context) []*ast.Diagnostic {
965960
return nil
966961
}
967962

968-
var globalDiagnostics []*ast.Diagnostic
969-
checkers, done := p.checkerPool.GetAllCheckers(ctx)
970-
defer done()
971-
for _, checker := range checkers {
972-
globalDiagnostics = append(globalDiagnostics, checker.GetGlobalDiagnostics()...)
973-
}
963+
globalDiagnostics := make([][]*ast.Diagnostic, p.checkerPool.Count())
964+
p.checkerPool.ForEachCheckerParallel(ctx, func(idx int, checker *checker.Checker) {
965+
globalDiagnostics[idx] = checker.GetGlobalDiagnostics()
966+
})
974967

975-
return SortAndDeduplicateDiagnostics(globalDiagnostics)
968+
return SortAndDeduplicateDiagnostics(slices.Concat(globalDiagnostics...))
976969
}
977970

978971
func (p *Program) GetDeclarationDiagnostics(ctx context.Context, sourceFile *ast.SourceFile) []*ast.Diagnostic {
@@ -1033,22 +1026,23 @@ func (p *Program) getSemanticDiagnosticsForFileNotFilter(ctx context.Context, so
10331026
defer done()
10341027
}
10351028
diags := slices.Clip(sourceFile.BindDiagnostics())
1036-
checkers, closeCheckers := p.checkerPool.GetAllCheckers(ctx)
1037-
defer closeCheckers()
10381029

10391030
// Ask for diags from all checkers; checking one file may add diagnostics to other files.
10401031
// These are deduplicated later.
1041-
for _, checker := range checkers {
1032+
checkerDiags := make([][]*ast.Diagnostic, p.checkerPool.Count())
1033+
p.checkerPool.ForEachCheckerParallel(ctx, func(idx int, checker *checker.Checker) {
10421034
if sourceFile == nil || checker == fileChecker {
1043-
diags = append(diags, checker.GetDiagnostics(ctx, sourceFile)...)
1035+
checkerDiags[idx] = checker.GetDiagnostics(ctx, sourceFile)
10441036
} else {
1045-
diags = append(diags, checker.GetDiagnosticsWithoutCheck(sourceFile)...)
1037+
checkerDiags[idx] = checker.GetDiagnosticsWithoutCheck(sourceFile)
10461038
}
1047-
}
1039+
})
10481040
if ctx.Err() != nil {
10491041
return nil
10501042
}
10511043

1044+
diags = append(diags, slices.Concat(checkerDiags...)...)
1045+
10521046
// !!! This should be rewritten to work like getBindAndCheckDiagnosticsForFileNoCache.
10531047

10541048
isPlainJS := ast.IsPlainJSFile(sourceFile, compilerOptions.CheckJs)
@@ -1140,22 +1134,20 @@ func (p *Program) getSuggestionDiagnosticsForFile(ctx context.Context, sourceFil
11401134

11411135
diags := slices.Clip(sourceFile.BindSuggestionDiagnostics)
11421136

1143-
checkers, closeCheckers := p.checkerPool.GetAllCheckers(ctx)
1144-
defer closeCheckers()
1145-
1146-
// Ask for diags from all checkers; checking one file may add diagnostics to other files.
1147-
// These are deduplicated later.
1148-
for _, checker := range checkers {
1137+
checkerDiags := make([][]*ast.Diagnostic, p.checkerPool.Count())
1138+
p.checkerPool.ForEachCheckerParallel(ctx, func(idx int, checker *checker.Checker) {
11491139
if sourceFile == nil || checker == fileChecker {
1150-
diags = append(diags, checker.GetSuggestionDiagnostics(ctx, sourceFile)...)
1140+
checkerDiags[idx] = checker.GetSuggestionDiagnostics(ctx, sourceFile)
11511141
} else {
11521142
// !!! is there any case where suggestion diagnostics are produced in other checkers?
11531143
}
1154-
}
1144+
})
11551145
if ctx.Err() != nil {
11561146
return nil
11571147
}
11581148

1149+
diags = append(diags, slices.Concat(checkerDiags...)...)
1150+
11591151
return diags
11601152
}
11611153

@@ -1251,32 +1243,28 @@ func (p *Program) SymbolCount() int {
12511243
for _, file := range p.files {
12521244
count += file.SymbolCount
12531245
}
1254-
checkers, done := p.checkerPool.GetAllCheckers(context.Background())
1255-
defer done()
1256-
for _, checker := range checkers {
1257-
count += int(checker.SymbolCount)
1258-
}
1259-
return count
1246+
var val atomic.Uint32
1247+
val.Store(uint32(count))
1248+
p.checkerPool.ForEachCheckerParallel(context.Background(), func(idx int, c *checker.Checker) {
1249+
val.Add(c.SymbolCount)
1250+
})
1251+
return int(val.Load())
12601252
}
12611253

12621254
func (p *Program) TypeCount() int {
1263-
var count int
1264-
checkers, done := p.checkerPool.GetAllCheckers(context.Background())
1265-
defer done()
1266-
for _, checker := range checkers {
1267-
count += int(checker.TypeCount)
1268-
}
1269-
return count
1255+
var val atomic.Uint32
1256+
p.checkerPool.ForEachCheckerParallel(context.Background(), func(idx int, c *checker.Checker) {
1257+
val.Add(c.TypeCount)
1258+
})
1259+
return int(val.Load())
12701260
}
12711261

12721262
func (p *Program) InstantiationCount() int {
1273-
var count int
1274-
checkers, done := p.checkerPool.GetAllCheckers(context.Background())
1275-
defer done()
1276-
for _, checker := range checkers {
1277-
count += int(checker.TotalInstantiationCount)
1278-
}
1279-
return count
1263+
var val atomic.Uint32
1264+
p.checkerPool.ForEachCheckerParallel(context.Background(), func(idx int, c *checker.Checker) {
1265+
val.Add(c.TotalInstantiationCount)
1266+
})
1267+
return int(val.Load())
12801268
}
12811269

12821270
func (p *Program) Program() *Program {

pkg/fourslash/_scripts/failingTests.txt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,6 @@ TestQuickInfoForTypeParameterInTypeAlias1
454454
TestQuickInfoForTypeParameterInTypeAlias2
455455
TestQuickInfoForTypeofParameter
456456
TestQuickInfoForUMDModuleAlias
457-
TestQuickInfoFromContextualType
458457
TestQuickInfoFunctionKeyword
459458
TestQuickInfoGenerics
460459
TestQuickInfoGetterSetter
@@ -471,7 +470,6 @@ TestQuickInfoJsDocNonDiscriminatedUnionSharedProp
471470
TestQuickInfoJsdocTypedefMissingType
472471
TestQuickInfoMappedSpreadTypes
473472
TestQuickInfoMappedType
474-
TestQuickInfoMappedTypeMethods
475473
TestQuickInfoMappedTypeRecursiveInference
476474
TestQuickInfoModuleVariables
477475
TestQuickInfoNarrowedTypeOfAliasSymbol
@@ -526,7 +524,6 @@ TestQuickInfoTypeError
526524
TestQuickInfoTypeOfThisInStatics
527525
TestQuickInfoTypeOnlyNamespaceAndClass
528526
TestQuickInfoUnionOfNamespaces
529-
TestQuickInfoUnion_discriminated
530527
TestQuickInfoWidenedTypes
531528
TestQuickInfo_notInsideComment
532529
TestQuickInforForSucessiveInferencesIsNotAny

pkg/fourslash/tests/gen/quickInfoFromContextualType_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99

1010
func TestQuickInfoFromContextualType(t *testing.T) {
1111
t.Parallel()
12-
t.Skip()
12+
1313
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
1414
const content = `// @Filename: quickInfoExportAssignmentOfGenericInterface_0.ts
1515
interface I {

pkg/fourslash/tests/gen/quickInfoMappedTypeMethods_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99

1010
func TestQuickInfoMappedTypeMethods(t *testing.T) {
1111
t.Parallel()
12-
t.Skip()
12+
1313
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
1414
const content = `type M = { [K in 'one']: any };
1515
const x: M = {

pkg/fourslash/tests/gen/quickInfoUnion_discriminated_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99

1010
func TestQuickInfoUnion_discriminated(t *testing.T) {
1111
t.Parallel()
12-
t.Skip()
12+
1313
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
1414
const content = `// @Filename: quickInfoJsDocTags.ts
1515
type U = A | B;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package fourslash_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/buke/typescript-go-internal/pkg/fourslash"
7+
"github.com/buke/typescript-go-internal/pkg/testutil"
8+
)
9+
10+
func TestQuickInfoFunction(t *testing.T) {
11+
t.Parallel()
12+
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
13+
const content = `/**/function foo() { return "hi"; }`
14+
15+
f := fourslash.NewFourslash(t, nil /*capabilities*/, content)
16+
f.VerifyQuickInfoAt(t, "", "function foo(): string", "")
17+
}

pkg/ls/hover.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ func (l *LanguageService) ProvideHover(ctx context.Context, documentURI lsproto.
2828
c, done := program.GetTypeCheckerForFile(ctx, file)
2929
defer done()
3030
rangeNode := getNodeForQuickInfo(node)
31-
quickInfo, documentation := l.getQuickInfoAndDocumentationForSymbol(c, c.GetSymbolAtLocation(node), rangeNode, contentFormat)
31+
symbol := getSymbolAtLocationForQuickInfo(c, node)
32+
quickInfo, documentation := l.getQuickInfoAndDocumentationForSymbol(c, symbol, rangeNode, contentFormat)
3233
if quickInfo == "" {
3334
return lsproto.HoverOrNull{}, nil
3435
}
@@ -282,6 +283,17 @@ func getNodeForQuickInfo(node *ast.Node) *ast.Node {
282283
return node
283284
}
284285

286+
func getSymbolAtLocationForQuickInfo(c *checker.Checker, node *ast.Node) *ast.Symbol {
287+
if objectElement := getContainingObjectLiteralElement(node); objectElement != nil {
288+
if contextualType := c.GetContextualType(objectElement.Parent, checker.ContextFlagsNone); contextualType != nil {
289+
if properties := c.GetPropertySymbolsFromContextualType(objectElement, contextualType, false /*unionSymbolOk*/); len(properties) == 1 {
290+
return properties[0]
291+
}
292+
}
293+
}
294+
return c.GetSymbolAtLocation(node)
295+
}
296+
285297
func inConstructorContext(node *ast.Node) bool {
286298
if node.Kind == ast.KindConstructorKeyword {
287299
return true

0 commit comments

Comments
 (0)