Skip to content

Commit

Permalink
Skip typechecking before declaration file on js files with nocheck
Browse files Browse the repository at this point in the history
  • Loading branch information
sheetalkamat committed May 20, 2024
1 parent d84431e commit 700c5b3
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 18 deletions.
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, skipCheck?: 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, skipCheck);
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, skipCheck: boolean | undefined) {
tracing?.push(tracing.Phase.Check, "checkSourceFile", { path: node.path }, /*separateBeginAndEnd*/ true);
performance.mark("beforeCheck");
checkSourceFileWorker(node);
checkSourceFileWorker(node, skipCheck);
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, skipCheck: boolean | undefined) {
const links = getNodeLinks(node);
if (!(links.flags & NodeCheckFlags.TypeChecked)) {
if (skipTypeChecking(node, compilerOptions, host)) {
if (skipCheck || 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, skipCheck?: boolean): Diagnostic[] {
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, skipCheck);
}
finally {
cancellationToken = undefined;
Expand All @@ -47599,7 +47599,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
deferredDiagnosticsCallbacks = [];
}

function checkSourceFileWithEagerDiagnostics(sourceFile: SourceFile) {
function checkSourceFileWithEagerDiagnostics(sourceFile: SourceFile, skipCheck?: 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, skipCheck);
addLazyDiagnostic = oldAddLazyDiagnostics;
}

function getDiagnosticsWorker(sourceFile: SourceFile): Diagnostic[] {
function getDiagnosticsWorker(sourceFile: SourceFile, skipCheck: 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, skipCheck);

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, skipCheck));
return diagnostics.getDiagnostics();
}

Expand Down
24 changes: 20 additions & 4 deletions src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2870,7 +2870,11 @@ 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 emitResolver = getTypeChecker().getEmitResolver(
options.outFile ? undefined : sourceFile,
cancellationToken,
forceDtsEmit && sourceFile && !canIncludeBindAndCheckDiagnsotics(sourceFile),
);

performance.mark("beforeEmit");

Expand Down Expand Up @@ -3006,14 +3010,12 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
const isJs = sourceFile.scriptKind === ScriptKind.JS || sourceFile.scriptKind === ScriptKind.JSX;
const isCheckJs = isJs && isCheckJsEnabledForFile(sourceFile, options);
const isPlainJs = isPlainJsFile(sourceFile, options.checkJs);
const isTsNoCheck = !!sourceFile.checkJsDirective && sourceFile.checkJsDirective.enabled === false;

// By default, only type-check .ts, .tsx, Deferred, plain JS, checked JS and External
// - plain JS: .js files with no // ts-check and checkJs: undefined
// - check JS: .js files with either // ts-check or checkJs: true
// - external: files that are added by plugins
const includeBindAndCheckDiagnostics = !isTsNoCheck && (sourceFile.scriptKind === ScriptKind.TS || sourceFile.scriptKind === ScriptKind.TSX
|| sourceFile.scriptKind === ScriptKind.External || isPlainJs || isCheckJs || sourceFile.scriptKind === ScriptKind.Deferred);
const includeBindAndCheckDiagnostics = canIncludeBindAndCheckDiagnsotics(sourceFile);
let bindDiagnostics: readonly Diagnostic[] = includeBindAndCheckDiagnostics ? sourceFile.bindDiagnostics : emptyArray;
let checkDiagnostics = includeBindAndCheckDiagnostics ? typeChecker.getDiagnostics(sourceFile, cancellationToken) : emptyArray;
if (isPlainJs) {
Expand All @@ -3025,6 +3027,20 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
});
}

function canIncludeBindAndCheckDiagnsotics(sourceFile: SourceFile) {
const isJs = sourceFile.scriptKind === ScriptKind.JS || sourceFile.scriptKind === ScriptKind.JSX;
const isCheckJs = isJs && isCheckJsEnabledForFile(sourceFile, options);
const isPlainJs = isPlainJsFile(sourceFile, options.checkJs);
const isTsNoCheck = !!sourceFile.checkJsDirective && sourceFile.checkJsDirective.enabled === false;

// By default, only type-check .ts, .tsx, Deferred, plain JS, checked JS and External
// - plain JS: .js files with no // ts-check and checkJs: undefined
// - check JS: .js files with either // ts-check or checkJs: true
// - external: files that are added by plugins
return !isTsNoCheck && (sourceFile.scriptKind === ScriptKind.TS || sourceFile.scriptKind === ScriptKind.TSX
|| sourceFile.scriptKind === ScriptKind.External || isPlainJs || isCheckJs || sourceFile.scriptKind === ScriptKind.Deferred);
}

function getMergedBindAndCheckDiagnostics(sourceFile: SourceFile, includeBindAndCheckDiagnostics: boolean, ...allDiagnostics: (readonly Diagnostic[] | undefined)[]) {
const flatDiagnostics = flatten(allDiagnostics);
if (!includeBindAndCheckDiagnostics || !sourceFile.commentDirectives?.length) {
Expand Down
2 changes: 1 addition & 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, skipCheck?: boolean): EmitResolver;

/** @internal */ getNodeCount(): number;
/** @internal */ getIdentifierCount(): number;
Expand Down

0 comments on commit 700c5b3

Please sign in to comment.