1
1
package checker
2
2
3
3
import (
4
+ "context"
4
5
"fmt"
5
6
"iter"
6
7
"maps"
@@ -567,6 +568,7 @@ type Checker struct {
567
568
useUnknownInCatchVariables bool
568
569
exactOptionalPropertyTypes bool
569
570
canCollectSymbolAliasAccessibilityData bool
571
+ wasCanceled bool
570
572
arrayVariances []VarianceFlags
571
573
globals ast.SymbolTable
572
574
globalSymbols []*ast.Symbol
@@ -824,6 +826,7 @@ type Checker struct {
824
826
_jsxNamespace string
825
827
_jsxFactoryEntity *ast.Node
826
828
skipDirectInferenceNodes core.Set[*ast.Node]
829
+ ctx context.Context
827
830
}
828
831
829
832
func NewChecker(program Program) *Checker {
@@ -2045,16 +2048,18 @@ func (c *Checker) getSymbol(symbols ast.SymbolTable, name string, meaning ast.Sy
2045
2048
return nil
2046
2049
}
2047
2050
2048
- func (c *Checker) CheckSourceFile(sourceFile *ast.SourceFile) {
2051
+ func (c *Checker) CheckSourceFile(ctx context.Context, sourceFile *ast.SourceFile) {
2049
2052
if SkipTypeChecking(sourceFile, c.compilerOptions) {
2050
2053
return
2051
2054
}
2052
- c.checkSourceFile(sourceFile)
2055
+ c.checkSourceFile(ctx, sourceFile)
2053
2056
}
2054
2057
2055
- func (c *Checker) checkSourceFile(sourceFile *ast.SourceFile) {
2058
+ func (c *Checker) checkSourceFile(ctx context.Context, sourceFile *ast.SourceFile) {
2059
+ c.checkNotCanceled()
2056
2060
links := c.sourceFileLinks.Get(sourceFile)
2057
2061
if !links.typeChecked {
2062
+ c.ctx = ctx
2058
2063
// Grammar checking
2059
2064
c.checkGrammarSourceFile(sourceFile)
2060
2065
c.renamedBindingElementsInTypes = nil
@@ -2065,19 +2070,27 @@ func (c *Checker) checkSourceFile(sourceFile *ast.SourceFile) {
2065
2070
c.checkExternalModuleExports(sourceFile.AsNode())
2066
2071
c.registerForUnusedIdentifiersCheck(sourceFile.AsNode())
2067
2072
}
2068
- // This relies on the results of other lazy diagnostics, so must be computed after them
2069
- if !sourceFile.IsDeclarationFile && (c.compilerOptions.NoUnusedLocals.IsTrue() || c.compilerOptions.NoUnusedParameters.IsTrue()) {
2070
- c.checkUnusedIdentifiers(links.identifierCheckNodes)
2071
- }
2072
- if !sourceFile.IsDeclarationFile {
2073
- c.checkUnusedRenamedBindingElements()
2073
+ if ctx.Err() == nil {
2074
+ // This relies on the results of other lazy diagnostics, so must be computed after them
2075
+ if !sourceFile.IsDeclarationFile && (c.compilerOptions.NoUnusedLocals.IsTrue() || c.compilerOptions.NoUnusedParameters.IsTrue()) {
2076
+ c.checkUnusedIdentifiers(links.identifierCheckNodes)
2077
+ }
2078
+ if !sourceFile.IsDeclarationFile {
2079
+ c.checkUnusedRenamedBindingElements()
2080
+ }
2081
+ } else {
2082
+ c.wasCanceled = true
2074
2083
}
2084
+ c.ctx = nil
2075
2085
links.typeChecked = true
2076
2086
}
2077
2087
}
2078
2088
2079
2089
func (c *Checker) checkSourceElements(nodes []*ast.Node) {
2080
2090
for _, node := range nodes {
2091
+ if c.isCanceled() {
2092
+ break
2093
+ }
2081
2094
c.checkSourceElement(node)
2082
2095
}
2083
2096
}
@@ -2094,7 +2107,6 @@ func (c *Checker) checkSourceElement(node *ast.Node) bool {
2094
2107
}
2095
2108
2096
2109
func (c *Checker) checkSourceElementWorker(node *ast.Node) {
2097
- // !!! Cancellation
2098
2110
kind := node.Kind
2099
2111
if kind >= ast.KindFirstStatement && kind <= ast.KindLastStatement {
2100
2112
flowNode := node.FlowNodeData().FlowNode
@@ -2246,6 +2258,9 @@ func (c *Checker) checkNodeDeferred(node *ast.Node) {
2246
2258
func (c *Checker) checkDeferredNodes(context *ast.SourceFile) {
2247
2259
links := c.sourceFileLinks.Get(context)
2248
2260
for node := range links.deferredNodes.Values() {
2261
+ if c.isCanceled() {
2262
+ break
2263
+ }
2249
2264
c.checkDeferredNode(node)
2250
2265
}
2251
2266
links.deferredNodes.Clear()
@@ -2291,6 +2306,9 @@ func (c *Checker) checkJSDocNodes(sourceFile *ast.SourceFile) {
2291
2306
// set parent references in JSDoc nodes.
2292
2307
for location, jsdocs := range sourceFile.JSDocCache() {
2293
2308
for _, jsdoc := range jsdocs {
2309
+ if c.isCanceled() {
2310
+ return
2311
+ }
2294
2312
c.checkJSDocComments(jsdoc, location)
2295
2313
tags := jsdoc.AsJSDoc().Tags
2296
2314
if tags != nil {
@@ -3510,10 +3528,10 @@ func (c *Checker) checkBlock(node *ast.Node) {
3510
3528
}
3511
3529
if ast.IsFunctionOrModuleBlock(node) {
3512
3530
saveFlowAnalysisDisabled := c.flowAnalysisDisabled
3513
- node.ForEachChild(c.checkSourceElement )
3531
+ c.checkSourceElements(node.Statements() )
3514
3532
c.flowAnalysisDisabled = saveFlowAnalysisDisabled
3515
3533
} else {
3516
- node.ForEachChild(c.checkSourceElement )
3534
+ c.checkSourceElements(node.Statements() )
3517
3535
}
3518
3536
if len(node.Locals()) != 0 {
3519
3537
c.registerForUnusedIdentifiersCheck(node)
@@ -13134,22 +13152,31 @@ func (c *Checker) getCannotFindNameDiagnosticForName(node *ast.Node) *diagnostic
13134
13152
}
13135
13153
}
13136
13154
13137
- func (c *Checker) GetDiagnostics(sourceFile *ast.SourceFile) []*ast.Diagnostic {
13155
+ func (c *Checker) GetDiagnostics(ctx context.Context, sourceFile *ast.SourceFile) []*ast.Diagnostic {
13156
+ c.checkNotCanceled()
13138
13157
if sourceFile != nil {
13139
- c.CheckSourceFile(sourceFile)
13158
+ c.CheckSourceFile(ctx, sourceFile)
13159
+ if c.wasCanceled {
13160
+ return nil
13161
+ }
13140
13162
return c.diagnostics.GetDiagnosticsForFile(sourceFile.FileName())
13141
13163
}
13142
13164
for _, file := range c.files {
13143
- c.CheckSourceFile(file)
13165
+ c.CheckSourceFile(ctx, file)
13166
+ if c.wasCanceled {
13167
+ return nil
13168
+ }
13144
13169
}
13145
13170
return c.diagnostics.GetDiagnostics()
13146
13171
}
13147
13172
13148
13173
func (c *Checker) GetDiagnosticsWithoutCheck(sourceFile *ast.SourceFile) []*ast.Diagnostic {
13174
+ c.checkNotCanceled()
13149
13175
return c.diagnostics.GetDiagnosticsForFile(sourceFile.FileName())
13150
13176
}
13151
13177
13152
13178
func (c *Checker) GetGlobalDiagnostics() []*ast.Diagnostic {
13179
+ c.checkNotCanceled()
13153
13180
return c.diagnostics.GetGlobalDiagnostics()
13154
13181
}
13155
13182
@@ -29800,7 +29827,7 @@ func (c *Checker) GetEmitResolver(file *ast.SourceFile, skipDiagnostics bool) pr
29800
29827
// emitter questions of this resolver will return the right information.
29801
29828
c.emitResolver.checkerMu.Lock()
29802
29829
defer c.emitResolver.checkerMu.Unlock()
29803
- c.checkSourceFile(file)
29830
+ c.checkSourceFile(context.Background(), file)
29804
29831
}
29805
29832
return c.emitResolver
29806
29833
}
0 commit comments