[2.0.x] Remove Path type from caching (#9036)

**Problem**
Like File, Path normally captures the absolute path,
so likely not a good candidate for caching.

**Solution**
Ban it.

---------

Co-authored-by: Anatolii Kmetiuk <anatoliikmt@proton.me>
This commit is contained in:
eugene yokota 2026-04-06 23:10:27 -04:00 committed by GitHub
parent 91be1a2f7e
commit 542591ea20
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 22 additions and 4 deletions

View File

@ -3,6 +3,8 @@ package internal
package util package util
package appmacro package appmacro
import java.io.File
import java.nio.file.{ Path as NioPath }
import scala.collection.mutable.ListBuffer import scala.collection.mutable.ListBuffer
import scala.reflect.ClassTag import scala.reflect.ClassTag
import scala.quoted.* import scala.quoted.*
@ -177,11 +179,11 @@ trait Cont:
val (expr, treeType) = eitherTree match val (expr, treeType) = eitherTree match
case Left(l) => (l, TypeRepr.of[Effect[A]]) case Left(l) => (l, TypeRepr.of[Effect[A]])
case Right(r) => (r, faTpe) case Right(r) => (r, faTpe)
val fileRepr = TypeRepr.of[File]
val pathRepr = TypeRepr.of[NioPath]
def containsFileType[A1: Type]: Boolean = def containsFileType[A1: Type]: Boolean =
val fileRepr = TypeRepr.of[java.io.File]
def containsFile(tpe: TypeRepr): Boolean = def containsFile(tpe: TypeRepr): Boolean =
if tpe =:= fileRepr then true if tpe =:= fileRepr || tpe =:= pathRepr then true
else else
tpe.dealias match tpe.dealias match
case AppliedType(_, args) => args.exists(containsFile) case AppliedType(_, args) => args.exists(containsFile)
@ -354,7 +356,7 @@ trait Cont:
)(body: Expr[A1], input: Expr[A2]): Expr[A1] = )(body: Expr[A1], input: Expr[A2]): Expr[A1] =
if containsFileType[A1] then if containsFileType[A1] then
report.errorAndAbort( report.errorAndAbort(
s"""java.io.File is not a valid output type for a cached task. s"""java.io.File and Path are not valid output types for a cached task.
|Consider using one of the following alternatives: |Consider using one of the following alternatives:
| - xsbti.HashedVirtualFileRef | - xsbti.HashedVirtualFileRef
| - xsbti.VirtualFileRef | - xsbti.VirtualFileRef

View File

@ -28,8 +28,11 @@ object Keys {
case object IgnoreSourceChanges extends WatchBuildSourceOption case object IgnoreSourceChanges extends WatchBuildSourceOption
case object WarnOnSourceChanges extends WatchBuildSourceOption case object WarnOnSourceChanges extends WatchBuildSourceOption
case object ReloadOnSourceChanges extends WatchBuildSourceOption case object ReloadOnSourceChanges extends WatchBuildSourceOption
@transient
val allInputFiles = val allInputFiles =
taskKey[Seq[Path]]("All of the file inputs for a task excluding directories and hidden files.") taskKey[Seq[Path]]("All of the file inputs for a task excluding directories and hidden files.")
@transient
val changedInputFiles = val changedInputFiles =
taskKey[Seq[(Path, FileStamp)] => FileChanges]("The changed files for a task") taskKey[Seq[(Path, FileStamp)] => FileChanges]("The changed files for a task")
val fileInputs = settingKey[Seq[Glob]]( val fileInputs = settingKey[Seq[Glob]](
@ -50,8 +53,10 @@ object Keys {
settingKey[PathFilter]("A filter to apply to the outputs of a task.") settingKey[PathFilter]("A filter to apply to the outputs of a task.")
val fileOutputExcludeFilter = val fileOutputExcludeFilter =
settingKey[PathFilter]("An exclusion filter to apply to the outputs of a task.") settingKey[PathFilter]("An exclusion filter to apply to the outputs of a task.")
@transient
val allOutputFiles = val allOutputFiles =
taskKey[Seq[Path]]("All of the file outputs for a task excluding directories and hidden files.") taskKey[Seq[Path]]("All of the file outputs for a task excluding directories and hidden files.")
@transient
val changedOutputFiles = val changedOutputFiles =
taskKey[Seq[(Path, FileStamp)] => FileChanges]( taskKey[Seq[(Path, FileStamp)] => FileChanges](
"The files that have changed since the last task run." "The files that have changed since the last task run."
@ -158,9 +163,12 @@ object Keys {
private[sbt] val dynamicFileOutputs = private[sbt] val dynamicFileOutputs =
taskKey[Seq[Path]]("The outputs of a task").withRank(Invisible) taskKey[Seq[Path]]("The outputs of a task").withRank(Invisible)
@transient
val inputFileStamps = val inputFileStamps =
taskKey[Seq[(Path, FileStamp)]]("Retrieves the hashes for a set of task input files") taskKey[Seq[(Path, FileStamp)]]("Retrieves the hashes for a set of task input files")
.withRank(Invisible) .withRank(Invisible)
@transient
val outputFileStamps = val outputFileStamps =
taskKey[Seq[(Path, FileStamp)]]("Retrieves the hashes for a set of task output files") taskKey[Seq[(Path, FileStamp)]]("Retrieves the hashes for a set of task output files")
.withRank(Invisible) .withRank(Invisible)
@ -181,9 +189,11 @@ object Keys {
private[sbt] val managedFileStampCache = taskKey[FileStamp.Cache]( private[sbt] val managedFileStampCache = taskKey[FileStamp.Cache](
"Map of managed file stamps that may be cleared between task evaluation runs." "Map of managed file stamps that may be cleared between task evaluation runs."
).withRank(Invisible) ).withRank(Invisible)
@transient
private[sbt] val managedSourcePaths = private[sbt] val managedSourcePaths =
taskKey[Seq[Path]]("Transforms the managedSources to Seq[Path] to induce setting injection.") taskKey[Seq[Path]]("Transforms the managedSources to Seq[Path] to induce setting injection.")
.withRank(Invisible) .withRank(Invisible)
@transient
private[sbt] val dependencyClasspathFiles = private[sbt] val dependencyClasspathFiles =
taskKey[Seq[Path]]("The dependency classpath for a task.").withRank(Invisible) taskKey[Seq[Path]]("The dependency classpath for a task.").withRank(Invisible)
private[sbt] val compileOutputs = taskKey[Seq[Path]]("Compilation outputs").withRank(Invisible) private[sbt] val compileOutputs = taskKey[Seq[Path]]("Compilation outputs").withRank(Invisible)

View File

@ -1,6 +1,7 @@
import java.nio.file.{ Path, Paths } import java.nio.file.{ Path, Paths }
import sbt.internal.FileChangesMacro.inputFiles import sbt.internal.FileChangesMacro.inputFiles
@transient
val foo = taskKey[Seq[Path]]("Copy files") val foo = taskKey[Seq[Path]]("Copy files")
foo / fileInputs += baseDirectory.value.toGlob / "base" / "*.txt" foo / fileInputs += baseDirectory.value.toGlob / "base" / "*.txt"
foo / target := baseDirectory.value / "out" foo / target := baseDirectory.value / "out"

View File

@ -2,6 +2,7 @@ import java.nio.file.{ Files, Path }
import sbt.internal.FileChangesMacro.inputFiles import sbt.internal.FileChangesMacro.inputFiles
import sbt.internal.FileChangesMacro.outputFiles import sbt.internal.FileChangesMacro.outputFiles
@transient
val copyPaths = taskKey[Seq[Path]]("Copy paths") val copyPaths = taskKey[Seq[Path]]("Copy paths")
copyPaths / fileInputs += baseDirectory.value.toGlob / "inputs" / * copyPaths / fileInputs += baseDirectory.value.toGlob / "inputs" / *
copyPaths := { copyPaths := {

View File

@ -1,5 +1,6 @@
import java.nio.file.{ Files, Path } import java.nio.file.{ Files, Path }
@transient
val outputTask = taskKey[Seq[Path]]("A task that generates outputs") val outputTask = taskKey[Seq[Path]]("A task that generates outputs")
outputTask := { outputTask := {
val dir = Files.createDirectories(streams.value.cacheDirectory.toPath) val dir = Files.createDirectories(streams.value.cacheDirectory.toPath)

View File

@ -1,5 +1,6 @@
import java.nio.file.Path import java.nio.file.Path
@transient
val foo = taskKey[Path]("foo") val foo = taskKey[Path]("foo")
// Check a direct override // Check a direct override
foo / outputFileStamps := Nil foo / outputFileStamps := Nil
@ -7,12 +8,14 @@ foo := baseDirectory.value.toPath / "foo.txt"
TaskKey[Unit]("checkFoo") := assert((foo / outputFileStamps).value == Nil) TaskKey[Unit]("checkFoo") := assert((foo / outputFileStamps).value == Nil)
@transient
val bar = taskKey[Path]("bar") val bar = taskKey[Path]("bar")
// Check an append // Check an append
bar / outputFileStamps ++= (baz / outputFileStamps).value bar / outputFileStamps ++= (baz / outputFileStamps).value
bar / outputFileStamps ++= (baz / outputFileStamps).value bar / outputFileStamps ++= (baz / outputFileStamps).value
bar := baseDirectory.value.toPath / "bar.txt" bar := baseDirectory.value.toPath / "bar.txt"
@transient
val baz = taskKey[Path]("baz") val baz = taskKey[Path]("baz")
baz := baseDirectory.value.toPath / "baz.txt" baz := baseDirectory.value.toPath / "baz.txt"