Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skip typechecking file when generating declaraiton to get d.ts signature for incremental build #58592

Merged
merged 7 commits into from
May 21, 2024
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);
sheetalkamat marked this conversation as resolved.
Show resolved Hide resolved
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[] {
sheetalkamat marked this conversation as resolved.
Show resolved Hide resolved
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::", () => {
sheetalkamat marked this conversation as resolved.
Show resolved Hide resolved
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