@@ -104,14 +104,14 @@ namespace ts {
104104 } ;
105105 }
106106
107- export function getPreEmitDiagnostics ( program : Program , sourceFile ?: SourceFile ) : Diagnostic [ ] {
108- let diagnostics = program . getOptionsDiagnostics ( ) . concat (
109- program . getSyntacticDiagnostics ( sourceFile ) ,
110- program . getGlobalDiagnostics ( ) ,
111- program . getSemanticDiagnostics ( sourceFile ) ) ;
107+ export function getPreEmitDiagnostics ( program : Program , sourceFile ?: SourceFile , cancellationToken ?: CancellationToken ) : Diagnostic [ ] {
108+ let diagnostics = program . getOptionsDiagnostics ( cancellationToken ) . concat (
109+ program . getSyntacticDiagnostics ( sourceFile , cancellationToken ) ,
110+ program . getGlobalDiagnostics ( cancellationToken ) ,
111+ program . getSemanticDiagnostics ( sourceFile , cancellationToken ) ) ;
112112
113113 if ( program . getCompilerOptions ( ) . declaration ) {
114- diagnostics . concat ( program . getDeclarationDiagnostics ( sourceFile ) ) ;
114+ diagnostics . concat ( program . getDeclarationDiagnostics ( sourceFile , cancellationToken ) ) ;
115115 }
116116
117117 return sortAndDeduplicateDiagnostics ( diagnostics ) ;
@@ -233,10 +233,15 @@ namespace ts {
233233 return noDiagnosticsTypeChecker || ( noDiagnosticsTypeChecker = createTypeChecker ( program , /*produceDiagnostics:*/ false ) ) ;
234234 }
235235
236- function emit ( sourceFile ?: SourceFile , writeFileCallback ?: WriteFileCallback ) : EmitResult {
236+ function emit ( sourceFile ?: SourceFile , writeFileCallback ?: WriteFileCallback , cancellationToken ?: CancellationToken ) : EmitResult {
237+ return runWithCancellationToken ( ( ) => emitWorker ( this , sourceFile , writeFileCallback , cancellationToken ) ) ;
238+ }
239+
240+ function emitWorker ( program : Program , sourceFile : SourceFile , writeFileCallback : WriteFileCallback , cancellationToken : CancellationToken ) : EmitResult {
237241 // If the noEmitOnError flag is set, then check if we have any errors so far. If so,
238- // immediately bail out.
239- if ( options . noEmitOnError && getPreEmitDiagnostics ( this ) . length > 0 ) {
242+ // immediately bail out. Note that we pass 'undefined' for 'sourceFile' so that we
243+ // get any preEmit diagnostics, not just the ones
244+ if ( options . noEmitOnError && getPreEmitDiagnostics ( program , /*sourceFile:*/ undefined , cancellationToken ) . length > 0 ) {
240245 return { diagnostics : [ ] , sourceMaps : undefined , emitSkipped : true } ;
241246 }
242247
@@ -265,53 +270,86 @@ namespace ts {
265270 return filesByName . get ( fileName ) ;
266271 }
267272
268- function getDiagnosticsHelper ( sourceFile : SourceFile , getDiagnostics : ( sourceFile : SourceFile ) => Diagnostic [ ] ) : Diagnostic [ ] {
273+ function getDiagnosticsHelper (
274+ sourceFile : SourceFile ,
275+ getDiagnostics : ( sourceFile : SourceFile , cancellationToken : CancellationToken ) => Diagnostic [ ] ,
276+ cancellationToken : CancellationToken ) : Diagnostic [ ] {
269277 if ( sourceFile ) {
270- return getDiagnostics ( sourceFile ) ;
278+ return getDiagnostics ( sourceFile , cancellationToken ) ;
271279 }
272280
273281 let allDiagnostics : Diagnostic [ ] = [ ] ;
274282 forEach ( program . getSourceFiles ( ) , sourceFile => {
275- addRange ( allDiagnostics , getDiagnostics ( sourceFile ) ) ;
283+ if ( cancellationToken ) {
284+ cancellationToken . throwIfCancellationRequested ( ) ;
285+ }
286+ addRange ( allDiagnostics , getDiagnostics ( sourceFile , cancellationToken ) ) ;
276287 } ) ;
277288
278289 return sortAndDeduplicateDiagnostics ( allDiagnostics ) ;
279290 }
280291
281- function getSyntacticDiagnostics ( sourceFile ? : SourceFile ) : Diagnostic [ ] {
282- return getDiagnosticsHelper ( sourceFile , getSyntacticDiagnosticsForFile ) ;
292+ function getSyntacticDiagnostics ( sourceFile : SourceFile , cancellationToken : CancellationToken ) : Diagnostic [ ] {
293+ return getDiagnosticsHelper ( sourceFile , getSyntacticDiagnosticsForFile , cancellationToken ) ;
283294 }
284295
285- function getSemanticDiagnostics ( sourceFile ? : SourceFile ) : Diagnostic [ ] {
286- return getDiagnosticsHelper ( sourceFile , getSemanticDiagnosticsForFile ) ;
296+ function getSemanticDiagnostics ( sourceFile : SourceFile , cancellationToken : CancellationToken ) : Diagnostic [ ] {
297+ return getDiagnosticsHelper ( sourceFile , getSemanticDiagnosticsForFile , cancellationToken ) ;
287298 }
288299
289- function getDeclarationDiagnostics ( sourceFile ? : SourceFile ) : Diagnostic [ ] {
290- return getDiagnosticsHelper ( sourceFile , getDeclarationDiagnosticsForFile ) ;
300+ function getDeclarationDiagnostics ( sourceFile : SourceFile , cancellationToken : CancellationToken ) : Diagnostic [ ] {
301+ return getDiagnosticsHelper ( sourceFile , getDeclarationDiagnosticsForFile , cancellationToken ) ;
291302 }
292303
293- function getSyntacticDiagnosticsForFile ( sourceFile : SourceFile ) : Diagnostic [ ] {
304+ function getSyntacticDiagnosticsForFile ( sourceFile : SourceFile , cancellationToken : CancellationToken ) : Diagnostic [ ] {
294305 return sourceFile . parseDiagnostics ;
295306 }
296307
297- function getSemanticDiagnosticsForFile ( sourceFile : SourceFile ) : Diagnostic [ ] {
298- let typeChecker = getDiagnosticsProducingTypeChecker ( ) ;
308+ function runWithCancellationToken < T > ( func : ( ) => T ) : T {
309+ try {
310+ return func ( ) ;
311+ }
312+ catch ( e ) {
313+ if ( e instanceof OperationCanceledException ) {
314+ // We were canceled while performing the operation. Because our type checker
315+ // might be a bad state, we need to throw it away.
316+ //
317+ // Note: we are overly agressive here. We do not actually *have* to throw away
318+ // the "noDiagnosticsTypeChecker". However, for simplicity, i'd like to keep
319+ // the lifetimes of these two TypeCheckers the same. Also, we generally only
320+ // cancel when the user has made a change anyways. And, in that case, we (the
321+ // program instance) will get thrown away anyways. So trying to keep one of
322+ // these type checkers alive doesn't serve much purpose.
323+ noDiagnosticsTypeChecker = undefined ;
324+ diagnosticsProducingTypeChecker = undefined ;
325+ }
299326
300- Debug . assert ( ! ! sourceFile . bindDiagnostics ) ;
301- let bindDiagnostics = sourceFile . bindDiagnostics ;
302- let checkDiagnostics = typeChecker . getDiagnostics ( sourceFile ) ;
303- let programDiagnostics = diagnostics . getDiagnostics ( sourceFile . fileName ) ;
327+ throw e ;
328+ }
329+ }
330+
331+ function getSemanticDiagnosticsForFile ( sourceFile : SourceFile , cancellationToken : CancellationToken ) : Diagnostic [ ] {
332+ return runWithCancellationToken ( ( ) => {
333+ let typeChecker = getDiagnosticsProducingTypeChecker ( ) ;
304334
305- return bindDiagnostics . concat ( checkDiagnostics ) . concat ( programDiagnostics ) ;
335+ Debug . assert ( ! ! sourceFile . bindDiagnostics ) ;
336+ let bindDiagnostics = sourceFile . bindDiagnostics ;
337+ let checkDiagnostics = typeChecker . getDiagnostics ( sourceFile , cancellationToken ) ;
338+ let programDiagnostics = diagnostics . getDiagnostics ( sourceFile . fileName ) ;
339+
340+ return bindDiagnostics . concat ( checkDiagnostics ) . concat ( programDiagnostics ) ;
341+ } ) ;
306342 }
307343
308- function getDeclarationDiagnosticsForFile ( sourceFile : SourceFile ) : Diagnostic [ ] {
309- if ( ! isDeclarationFile ( sourceFile ) ) {
310- let resolver = getDiagnosticsProducingTypeChecker ( ) . getEmitResolver ( sourceFile ) ;
311- // Don't actually write any files since we're just getting diagnostics.
312- var writeFile : WriteFileCallback = ( ) => { } ;
313- return ts . getDeclarationDiagnostics ( getEmitHost ( writeFile ) , resolver , sourceFile ) ;
314- }
344+ function getDeclarationDiagnosticsForFile ( sourceFile : SourceFile , cancellationToken : CancellationToken ) : Diagnostic [ ] {
345+ return runWithCancellationToken ( ( ) => {
346+ if ( ! isDeclarationFile ( sourceFile ) ) {
347+ let resolver = getDiagnosticsProducingTypeChecker ( ) . getEmitResolver ( sourceFile , cancellationToken ) ;
348+ // Don't actually write any files since we're just getting diagnostics.
349+ var writeFile : WriteFileCallback = ( ) => { } ;
350+ return ts . getDeclarationDiagnostics ( getEmitHost ( writeFile ) , resolver , sourceFile ) ;
351+ }
352+ } ) ;
315353 }
316354
317355 function getOptionsDiagnostics ( ) : Diagnostic [ ] {
0 commit comments