Skip to content

Commit

Permalink
Skip typechecking file when generating declaraiton to get d.ts signat…
Browse files Browse the repository at this point in the history
…ure for incremental build (#58592)
  • Loading branch information
sheetalkamat authored May 21, 2024
1 parent 0684152 commit cd40d26
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 104 deletions.
4 changes: 2 additions & 2 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, skipDiagnostics?: 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);
if (!skipDiagnostics) getDiagnostics(sourceFile, cancellationToken);
return emitResolver;
}

Expand Down
11 changes: 10 additions & 1 deletion src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,11 @@ export function getFirstProjectOutput(configFile: ParsedCommandLine, ignoreCase:
return Debug.fail(`project ${configFile.options.configFilePath} expected to have at least one output`);
}

/** @internal */
export function emitResolverSkipsTypeChecking(emitOnly: boolean | EmitOnly | undefined, forceDtsEmit: boolean | undefined) {
return !!forceDtsEmit && !!emitOnly;
}

/** @internal */
// targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature
export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile | undefined, { scriptTransformers, declarationTransformers }: EmitTransformers, emitOnly?: boolean | EmitOnly, onlyBuildInfo?: boolean, forceDtsEmit?: boolean): EmitResult {
Expand Down Expand Up @@ -848,7 +853,11 @@ 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 ||
emitResolverSkipsTypeChecking(emitOnly, 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
28 changes: 19 additions & 9 deletions src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import {
EmitHost,
emitModuleKindIsNonNodeESM,
EmitOnly,
emitResolverSkipsTypeChecking,
EmitResult,
emptyArray,
ensureTrailingDirectorySeparator,
Expand Down Expand Up @@ -2870,18 +2871,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,
emitResolverSkipsTypeChecking(emitOnly, 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::", () => {
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

0 comments on commit cd40d26

Please sign in to comment.