Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
26 changes: 13 additions & 13 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2428,10 +2428,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return visitEachChild(node, markAsSynthetic, /*context*/ undefined);
}

function getEmitResolver(sourceFile: SourceFile, cancellationToken: CancellationToken) {
function getEmitResolver(sourceFile: SourceFile, cancellationToken: CancellationToken, forceDtsEmit?: boolean) {
// Ensure we have all the type information in place for this file so that all the
// emitter questions of this resolver will return the right information.
getDiagnostics(sourceFile, cancellationToken);
getDiagnostics(sourceFile, cancellationToken, forceDtsEmit);
Comment thread
sheetalkamat marked this conversation as resolved.
Outdated
return emitResolver;
}

Expand Down Expand Up @@ -47483,10 +47483,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
tracing?.pop();
}

function checkSourceFile(node: SourceFile) {
function checkSourceFile(node: SourceFile, forceDtsEmit: boolean | undefined) {
tracing?.push(tracing.Phase.Check, "checkSourceFile", { path: node.path }, /*separateBeginAndEnd*/ true);
performance.mark("beforeCheck");
checkSourceFileWorker(node);
checkSourceFileWorker(node, forceDtsEmit);
performance.mark("afterCheck");
performance.measure("Check", "beforeCheck", "afterCheck");
tracing?.pop();
Expand All @@ -47511,10 +47511,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}

// Fully type check a source file and collect the relevant diagnostics.
function checkSourceFileWorker(node: SourceFile) {
function checkSourceFileWorker(node: SourceFile, forceDtsEmit: boolean | undefined) {
const links = getNodeLinks(node);
if (!(links.flags & NodeCheckFlags.TypeChecked)) {
if (skipTypeChecking(node, compilerOptions, host)) {
if (forceDtsEmit || skipTypeChecking(node, compilerOptions, host)) {
return;
}

Expand Down Expand Up @@ -47578,13 +47578,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
}

function getDiagnostics(sourceFile: SourceFile, ct: CancellationToken): Diagnostic[] {
function getDiagnostics(sourceFile: SourceFile, ct: CancellationToken, forceDtsEmit?: boolean): Diagnostic[] {
Comment thread
sheetalkamat marked this conversation as resolved.
Outdated
try {
// Record the cancellation token so it can be checked later on during checkSourceElement.
// Do this in a finally block so we can ensure that it gets reset back to nothing after
// this call is done.
cancellationToken = ct;
return getDiagnosticsWorker(sourceFile);
return getDiagnosticsWorker(sourceFile, forceDtsEmit);
}
finally {
cancellationToken = undefined;
Expand All @@ -47599,7 +47599,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
deferredDiagnosticsCallbacks = [];
}

function checkSourceFileWithEagerDiagnostics(sourceFile: SourceFile) {
function checkSourceFileWithEagerDiagnostics(sourceFile: SourceFile, forceDtsEmit?: boolean) {
ensurePendingDiagnosticWorkComplete();
// then setup diagnostics for immediate invocation (as we are about to collect them, and
// this avoids the overhead of longer-lived callbacks we don't need to allocate)
Expand All @@ -47608,11 +47608,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// thus much more likely retaining the same union ordering as before we had lazy diagnostics)
const oldAddLazyDiagnostics = addLazyDiagnostic;
addLazyDiagnostic = cb => cb();
checkSourceFile(sourceFile);
checkSourceFile(sourceFile, forceDtsEmit);
addLazyDiagnostic = oldAddLazyDiagnostics;
}

function getDiagnosticsWorker(sourceFile: SourceFile): Diagnostic[] {
function getDiagnosticsWorker(sourceFile: SourceFile, forceDtsEmit: boolean | undefined): Diagnostic[] {
if (sourceFile) {
ensurePendingDiagnosticWorkComplete();
// Some global diagnostics are deferred until they are needed and
Expand All @@ -47621,7 +47621,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const previousGlobalDiagnostics = diagnostics.getGlobalDiagnostics();
const previousGlobalDiagnosticsSize = previousGlobalDiagnostics.length;

checkSourceFileWithEagerDiagnostics(sourceFile);
checkSourceFileWithEagerDiagnostics(sourceFile, forceDtsEmit);

const semanticDiagnostics = diagnostics.getDiagnostics(sourceFile.fileName);
const currentGlobalDiagnostics = diagnostics.getGlobalDiagnostics();
Expand All @@ -47642,7 +47642,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {

// Global diagnostics are always added when a file is not provided to
// getDiagnostics
forEach(host.getSourceFiles(), checkSourceFileWithEagerDiagnostics);
forEach(host.getSourceFiles(), sourceFile => checkSourceFileWithEagerDiagnostics(sourceFile, forceDtsEmit));
return diagnostics.getDiagnostics();
}

Expand Down
2 changes: 1 addition & 1 deletion src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -848,7 +848,7 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi
const filesForEmit = forceDtsEmit ? sourceFiles : filter(sourceFiles, isSourceFileNotJson);
// Setup and perform the transformation to retrieve declarations from the input files
const inputListOrBundle = compilerOptions.outFile ? [factory.createBundle(filesForEmit)] : filesForEmit;
if ((emitOnly && !getEmitDeclarations(compilerOptions)) || compilerOptions.noCheck) {
if ((emitOnly && !getEmitDeclarations(compilerOptions)) || compilerOptions.noCheck || forceDtsEmit) {
// Checker wont collect the linked aliases since thats only done when declaration is enabled and checking is performed.
// Do that here when emitting only dts files
filesForEmit.forEach(collectLinkedAliases);
Expand Down
27 changes: 18 additions & 9 deletions src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2870,18 +2870,27 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
// This is because in the -out scenario all files need to be emitted, and therefore all
// files need to be type checked. And the way to specify that all files need to be type
// checked is to not pass the file to getEmitResolver.
const emitResolver = getTypeChecker().getEmitResolver(options.outFile ? undefined : sourceFile, cancellationToken);
const typeChecker = getTypeChecker();
const emitResolver = typeChecker.getEmitResolver(
options.outFile ? undefined : sourceFile,
cancellationToken,
forceDtsEmit,
);

performance.mark("beforeEmit");

const emitResult = emitFiles(
emitResolver,
getEmitHost(writeFileCallback),
sourceFile,
getTransformers(options, customTransformers, emitOnly),
emitOnly,
/*onlyBuildInfo*/ false,
forceDtsEmit,
const emitResult = typeChecker.runWithCancellationToken(
cancellationToken,
() =>
emitFiles(
emitResolver,
getEmitHost(writeFileCallback),
sourceFile,
getTransformers(options, customTransformers, emitOnly),
emitOnly,
/*onlyBuildInfo*/ false,
forceDtsEmit,
),
);

performance.mark("afterEmit");
Expand Down
4 changes: 3 additions & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5264,7 +5264,7 @@ export interface TypeChecker {
// Should not be called directly. Should only be accessed through the Program instance.
/** @internal */ getDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[];
/** @internal */ getGlobalDiagnostics(): Diagnostic[];
/** @internal */ getEmitResolver(sourceFile?: SourceFile, cancellationToken?: CancellationToken): EmitResolver;
/** @internal */ getEmitResolver(sourceFile?: SourceFile, cancellationToken?: CancellationToken, forceDts?: boolean): EmitResolver;

/** @internal */ getNodeCount(): number;
/** @internal */ getIdentifierCount(): number;
Expand Down Expand Up @@ -5354,6 +5354,8 @@ export interface TypeChecker {
* and the operation is cancelled, then it should be discarded, otherwise it is safe to keep.
*/
runWithCancellationToken<T>(token: CancellationToken, cb: (checker: TypeChecker) => T): T;
/**@internal */
runWithCancellationToken<T>(token: CancellationToken | undefined, cb: (checker: TypeChecker) => T): T; // eslint-disable-line @typescript-eslint/unified-signatures

/** @internal */ getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol: Symbol): readonly TypeParameter[] | undefined;
/** @internal */ isDeclarationVisible(node: Declaration | AnyImportSyntax): boolean;
Expand Down
6 changes: 3 additions & 3 deletions src/testRunner/unittests/tsc/cancellationToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
libFile,
} from "../helpers/virtualFileSystemWithWatch.js";

describe("unittests:: tsc:: builder cancellationToken", () => {
describe("unittests:: tsc:: builder cancellationToken:: sheetal", () => {
Comment thread
sheetalkamat marked this conversation as resolved.
Outdated
verifyCancellation(/*useBuildInfo*/ true, "when emitting buildInfo");
verifyCancellation(/*useBuildInfo*/ false, "when using state");
function verifyCancellation(useBuildInfo: boolean, scenario: string) {
Expand All @@ -41,9 +41,9 @@ describe("unittests:: tsc:: builder cancellationToken", () => {
const cFile: File = {
path: `/user/username/projects/myproject/c.ts`,
content: Utils.dedent`
export class C {
export var C = class CReal {
d = 1;
}`,
};`,
};
const dFile: File = {
path: `/user/username/projects/myproject/d.ts`,
Expand Down
Loading