From a1114188b4fce09933430b13734516d482068c91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mai=20Huy=20Ho=C3=A0ng?= Date: Tue, 18 Aug 2026 22:40:54 +0700 Subject: [PATCH] [2.x] perf: Stop re-converting the classpath in compileOptions (#9622) Both compileOptions sites mapped the whole classpath through converter.toPath -> converter.toVirtualFile. Going through toPath defeats FileConverter.toVirtualFile(VirtualFileRef), which already returns the ref unchanged when it is a VirtualFile, so every entry was rebuilt from scratch. For a class directory that means walking the entire output tree, once per dependent. backendOutput is converted explicitly because it is a settingKey evaluated once at project load, so reusing it would pin the listing taken before anything compiled. Co-authored-by: Claude Opus 5 --- main/src/main/scala/sbt/Defaults.scala | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index dd9f5a930..42144b2f5 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -984,9 +984,10 @@ object Defaults extends BuildCommon with DefExtra { compileOptions := Def.uncached { val opts = (compile / compileOptions).value val cp0 = dependencyClasspath.value - val cp1 = backendOutput.value +: data(cp0) val converter = fileConverter.value - val cp = cp1.map(converter.toPath).map(converter.toVirtualFile) + // backendOutput is a settingKey: its listing is captured at project load, so re-convert + val cp = converter.toVirtualFile(converter.toPath(backendOutput.value)) +: + data(cp0).map(converter.toVirtualFile) opts.withClasspath(cp.toArray) }, compileInputs2 := Def.uncached { @@ -2469,8 +2470,8 @@ object Defaults extends BuildCommon with DefExtra { compileOptions := Def.uncached { val c = fileConverter.value val cp0 = classpathTask.value - val cp1 = backendOutput.value +: data(cp0) - val cp = cp1.map(c.toPath).map(c.toVirtualFile) + // backendOutput is a settingKey: its listing is captured at project load, so re-convert + val cp = c.toVirtualFile(c.toPath(backendOutput.value)) +: data(cp0).map(c.toVirtualFile) val vs0 = sourcesVF.value val vs = vs0.toVector.map: x => c.toVirtualFile(c.toPath(x))