Skip to content

Commit 7268f10

Browse files
committed
Prefer own references over indirect references when searching for resolved references
1 parent ca64946 commit 7268f10

File tree

2 files changed

+96
-55
lines changed

2 files changed

+96
-55
lines changed

src/compiler/program.ts

Lines changed: 66 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,7 +1137,11 @@ export function forEachResolvedProjectReference<T>(
11371137
resolvedProjectReferences: readonly (ResolvedProjectReference | undefined)[] | undefined,
11381138
cb: (resolvedProjectReference: ResolvedProjectReference, parent: ResolvedProjectReference | undefined) => T | undefined,
11391139
): T | undefined {
1140-
return forEachProjectReference(/*projectReferences*/ undefined, resolvedProjectReferences, (resolvedRef, parent) => resolvedRef && cb(resolvedRef, parent));
1140+
return forEachProjectReference(
1141+
/*projectReferences*/ undefined,
1142+
resolvedProjectReferences,
1143+
(resolvedRef, parent) => resolvedRef && cb(resolvedRef, parent),
1144+
);
11411145
}
11421146

11431147
function forEachProjectReference<T>(
@@ -1147,7 +1151,6 @@ function forEachProjectReference<T>(
11471151
cbRef?: (projectReferences: readonly ProjectReference[] | undefined, parent: ResolvedProjectReference | undefined) => T | undefined,
11481152
): T | undefined {
11491153
let seenResolvedRefs: Set<Path> | undefined;
1150-
11511154
return worker(projectReferences, resolvedProjectReferences, /*parent*/ undefined);
11521155

11531156
function worker(
@@ -1160,19 +1163,26 @@ function forEachProjectReference<T>(
11601163
const result = cbRef(projectReferences, parent);
11611164
if (result) return result;
11621165
}
1163-
1164-
return forEach(resolvedProjectReferences, (resolvedRef, index) => {
1165-
if (resolvedRef && seenResolvedRefs?.has(resolvedRef.sourceFile.path)) {
1166-
// ignore recursives
1167-
return undefined;
1168-
}
1169-
1170-
const result = cbResolvedRef(resolvedRef, parent, index);
1171-
if (result || !resolvedRef) return result;
1172-
1173-
(seenResolvedRefs ||= new Set()).add(resolvedRef.sourceFile.path);
1174-
return worker(resolvedRef.commandLine.projectReferences, resolvedRef.references, resolvedRef);
1175-
});
1166+
let skipChildren: Set<ResolvedProjectReference> | undefined;
1167+
return forEach(
1168+
resolvedProjectReferences,
1169+
(resolvedRef, index) => {
1170+
if (resolvedRef && seenResolvedRefs?.has(resolvedRef.sourceFile.path)) {
1171+
(skipChildren ??= new Set()).add(resolvedRef);
1172+
// ignore recursives
1173+
return undefined;
1174+
}
1175+
const result = cbResolvedRef(resolvedRef, parent, index);
1176+
if (result || !resolvedRef) return result;
1177+
(seenResolvedRefs ||= new Set()).add(resolvedRef.sourceFile.path);
1178+
},
1179+
) || forEach(
1180+
resolvedProjectReferences,
1181+
resolvedRef =>
1182+
resolvedRef && !skipChildren?.has(resolvedRef) ?
1183+
worker(resolvedRef.commandLine.projectReferences, resolvedRef.references, resolvedRef) :
1184+
undefined,
1185+
);
11761186
}
11771187
}
11781188

@@ -1354,7 +1364,14 @@ export function isProgramUptoDate(
13541364
(seenResolvedRefs || (seenResolvedRefs = [])).push(oldResolvedRef);
13551365

13561366
// If child project references are upto date, this project reference is uptodate
1357-
return !forEach(oldResolvedRef.references, (childResolvedRef, index) => !resolvedProjectReferenceUptoDate(childResolvedRef, oldResolvedRef.commandLine.projectReferences![index]));
1367+
return !forEach(
1368+
oldResolvedRef.references,
1369+
(childResolvedRef, index) =>
1370+
!resolvedProjectReferenceUptoDate(
1371+
childResolvedRef,
1372+
oldResolvedRef.commandLine.projectReferences![index],
1373+
),
1374+
);
13581375
}
13591376

13601377
// In old program, not able to resolve project reference path,
@@ -4883,7 +4900,14 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
48834900
case FileIncludeKind.SourceFromProjectReference:
48844901
case FileIncludeKind.OutputFromProjectReference:
48854902
const referencedResolvedRef = Debug.checkDefined(resolvedProjectReferences?.[reason.index]);
4886-
const referenceInfo = forEachProjectReference(projectReferences, resolvedProjectReferences, (resolvedRef, parent, index) => resolvedRef === referencedResolvedRef ? { sourceFile: parent?.sourceFile || options.configFile!, index } : undefined);
4903+
const referenceInfo = forEachProjectReference(
4904+
projectReferences,
4905+
resolvedProjectReferences,
4906+
(resolvedRef, parent, index) =>
4907+
resolvedRef === referencedResolvedRef ?
4908+
{ sourceFile: parent?.sourceFile || options.configFile!, index } :
4909+
undefined,
4910+
);
48874911
if (!referenceInfo) return undefined;
48884912
const { sourceFile, index } = referenceInfo;
48894913
const referencesSyntax = forEachTsConfigPropArray(sourceFile as TsConfigSourceFile, "references", property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined);
@@ -4923,28 +4947,32 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
49234947

49244948
function verifyProjectReferences() {
49254949
const buildInfoPath = !options.suppressOutputPathCheck ? getTsBuildInfoEmitOutputFilePath(options) : undefined;
4926-
forEachProjectReference(projectReferences, resolvedProjectReferences, (resolvedRef, parent, index) => {
4927-
const ref = (parent ? parent.commandLine.projectReferences : projectReferences)![index];
4928-
const parentFile = parent && parent.sourceFile as JsonSourceFile;
4929-
verifyDeprecatedProjectReference(ref, parentFile, index);
4930-
if (!resolvedRef) {
4931-
createDiagnosticForReference(parentFile, index, Diagnostics.File_0_not_found, ref.path);
4932-
return;
4933-
}
4934-
const options = resolvedRef.commandLine.options;
4935-
if (!options.composite || options.noEmit) {
4936-
// ok to not have composite if the current program is container only
4937-
const inputs = parent ? parent.commandLine.fileNames : rootNames;
4938-
if (inputs.length) {
4939-
if (!options.composite) createDiagnosticForReference(parentFile, index, Diagnostics.Referenced_project_0_must_have_setting_composite_Colon_true, ref.path);
4940-
if (options.noEmit) createDiagnosticForReference(parentFile, index, Diagnostics.Referenced_project_0_may_not_disable_emit, ref.path);
4950+
forEachProjectReference(
4951+
projectReferences,
4952+
resolvedProjectReferences,
4953+
(resolvedRef, parent, index) => {
4954+
const ref = (parent ? parent.commandLine.projectReferences : projectReferences)![index];
4955+
const parentFile = parent && parent.sourceFile as JsonSourceFile;
4956+
verifyDeprecatedProjectReference(ref, parentFile, index);
4957+
if (!resolvedRef) {
4958+
createDiagnosticForReference(parentFile, index, Diagnostics.File_0_not_found, ref.path);
4959+
return;
49414960
}
4942-
}
4943-
if (!parent && buildInfoPath && buildInfoPath === getTsBuildInfoEmitOutputFilePath(options)) {
4944-
createDiagnosticForReference(parentFile, index, Diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_file_generated_by_referenced_project_1, buildInfoPath, ref.path);
4945-
hasEmitBlockingDiagnostics.set(toPath(buildInfoPath), true);
4946-
}
4947-
});
4961+
const options = resolvedRef.commandLine.options;
4962+
if (!options.composite || options.noEmit) {
4963+
// ok to not have composite if the current program is container only
4964+
const inputs = parent ? parent.commandLine.fileNames : rootNames;
4965+
if (inputs.length) {
4966+
if (!options.composite) createDiagnosticForReference(parentFile, index, Diagnostics.Referenced_project_0_must_have_setting_composite_Colon_true, ref.path);
4967+
if (options.noEmit) createDiagnosticForReference(parentFile, index, Diagnostics.Referenced_project_0_may_not_disable_emit, ref.path);
4968+
}
4969+
}
4970+
if (!parent && buildInfoPath && buildInfoPath === getTsBuildInfoEmitOutputFilePath(options)) {
4971+
createDiagnosticForReference(parentFile, index, Diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_file_generated_by_referenced_project_1, buildInfoPath, ref.path);
4972+
hasEmitBlockingDiagnostics.set(toPath(buildInfoPath), true);
4973+
}
4974+
},
4975+
);
49484976
}
49494977

49504978
function createDiagnosticForOptionPathKeyValue(key: string, valueIndex: number, message: DiagnosticMessage, ...args: DiagnosticArguments) {

src/server/editorServices.ts

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -862,23 +862,36 @@ function forEachResolvedProjectReferenceProjectWorker<T>(
862862
seenResolvedRefs?: Map<string, ConfiguredProjectLoadKind>,
863863
): T | undefined {
864864
const loadKind = parentOptions.disableReferencedProjectLoad ? ConfiguredProjectLoadKind.Find : kind;
865-
return forEach(resolvedProjectReferences, ref => {
866-
if (!ref) return undefined;
867-
868-
const configFileName = toNormalizedPath(ref.sourceFile.fileName);
869-
const canonicalPath = projectService.toCanonicalFileName(configFileName);
870-
const seenValue = seenResolvedRefs?.get(canonicalPath);
871-
if (seenValue !== undefined && seenValue >= loadKind) {
872-
return undefined;
873-
}
874-
const result = cb(ref, loadKind);
875-
if (result) {
876-
return result;
877-
}
878-
879-
(seenResolvedRefs || (seenResolvedRefs = new Map())).set(canonicalPath, loadKind);
880-
return ref.references && forEachResolvedProjectReferenceProjectWorker(ref.references, ref.commandLine.options, cb, loadKind, projectService, seenResolvedRefs);
881-
});
865+
let skipChildren: Set<ResolvedProjectReference> | undefined;
866+
return forEach(
867+
resolvedProjectReferences,
868+
ref => {
869+
if (!ref) return undefined;
870+
const configFileName = toNormalizedPath(ref.sourceFile.fileName);
871+
const canonicalPath = projectService.toCanonicalFileName(configFileName);
872+
const seenValue = seenResolvedRefs?.get(canonicalPath);
873+
if (seenValue !== undefined && seenValue >= loadKind) {
874+
(skipChildren ??= new Set()).add(ref);
875+
return undefined;
876+
}
877+
const result = cb(ref, loadKind);
878+
if (result) return result;
879+
(seenResolvedRefs ??= new Map()).set(canonicalPath, loadKind);
880+
},
881+
) || forEach(
882+
resolvedProjectReferences,
883+
ref =>
884+
ref?.references && !skipChildren?.has(ref) ?
885+
forEachResolvedProjectReferenceProjectWorker(
886+
ref.references,
887+
ref.commandLine.options,
888+
cb,
889+
loadKind,
890+
projectService,
891+
seenResolvedRefs,
892+
) :
893+
undefined,
894+
);
882895
}
883896

884897
function forEachPotentialProjectReference<T>(

0 commit comments

Comments
 (0)