**problem**
.previous was implemented as an inline expansion to wrapInitTask(Previous.runtime(in)(<instance of JsonFormat[A1]))
For example, the .previous on taskKey[String] gets inlined like
this, and then sbt's macro moves `Previous.runtime(...)(using StringJsonFormat)` into task input.
lazy val fingerprints = taskKey[String]("...")
val previousFingerprints = fingerprints.previous
// inlined
val previousFingerprints: Option[String] = {
InputWrapper.wrapInitTask(
Previous.runtime(...)(using StringJsonFormat)
)
}
- 6c8ee6ea37/main-settings/src/main/scala/sbt/Def.scala (L410-L412)
- 6c8ee6ea37/core-macros/src/main/scala/sbt/internal/util/appmacro/Cont.scala (L468)
However, if the return type of task is a bit more complicated like
Seq[String], it doesn't work:
Scala 3 Compiler's inliner creates a synthetic proxy symbol if the
inlining tree is an application, whose arguments are unstable path.
For example,
lazy val fingerprints = taskKey[Seq[String]]("...")
val previousFingerprints = fingerprints.previous
// inline to
val previousFingerprints: Option[Seq[String]] = {
val x$2$proxy1 = immSeqFormat(StringJsonFormat)
InputWrapper.wrapInitTask(
Previous.runtime(...)(using x$2$proxy1)
)
}
cc7d6db700/compiler/src/dotty/tools/dotc/inlines/Inliner.scala (L324-L329)
However, sbt2's Cont macro captures only `Previous.runtime(...)(using x$2$proxy1)`, while it doesn't capture the proxy definition. Consequently, while sbt macro moves the `Previous.runtime(...)` application as a task input, the proxy definition is left in the task body.
mapN(
(
link / fingerprints,
Previous.runtime(...)(using x$2$proxy1) // here x$2$proxy1 can't be found
)
) {
...
val x$2$proxy1 = ...
}
Then we get:
-- Error: /.../build.sbt:14:59
14 | val previousFingerprints = (link / fingerprints).previous
| ^
|While expanding a macro, a reference to value x$2$proxy1 was used outside the scope where it was defined
**How this PR fixed**
This commit fixes the problem by defining a dedicated Scala3 macro for .previous that summon JsonFormat[A1] inside the macro before constructing the wrapped previous.runtime(...)(using ...) by inliner. The macro insert the found given value tree directly into the previous.runtime(...)(using $found).
This way, Cont macro always moves the Previous.runtime tree along with it's given argument, without leaking compiler-generated inline proxies across scopes.
* [2.x] feat: Add cacheVersion setting for global cache invalidation
**Problem**
There was no escape hatch to invalidate all task caches when needed.
**Solution**
Add `Global / cacheVersion` setting that incorporates into the cache key
hash. Changing it invalidates all caches. Defaults to reading system
property `sbt.cacheversion`, or else 0L. When 0L, the hash is identical
to the previous behavior (backward compatible).
Fixes#8992
* [2.x] refactor: Simplify BuildWideCacheConfiguration and add cacheVersion test
- Replace auxiliary constructors with default parameter values
- Add unit test verifying cacheVersion invalidates the cache
* [2.x] fix: Restore auxiliary constructors for binary compatibility
* [2.x] test: Improve cacheVersion scripted test and add release note
- Scripted test now verifies cache invalidation via a counter
that increments only when the task body actually executes
- Add release note documenting the cacheVersion setting
Fixes#1144
The compileTimeOnly message on wrapInitInputTask said "`value` can
only be called on an input task..." when the user called `.evaluated`,
not `.value`. Changed to say `evaluated` and suggest `.toTask(" <args>").value`
as an alternative.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Treat explicit plugin toggles as last-call-wins for the same plugin.
This avoids contradictory include/exclude states when disablePlugins(X) is followed by
enablePlugins(X) (and vice versa), aligning behavior with normal override expectations.
Apply the same semantics to ProjectMatrix and add regression coverage:
- unit tests in main/src/test/scala/ProjectSpec.scala
- scripted test in sbt-app/src/sbt-test/project/i1926-disable-enable-plugin
**Problem**
The configuration name translation in logging was incorrect. When a
configuration like MultiJvm (id="MultiJvm", name="multi-jvm") was
displayed, it showed "Multi-jvm" instead of "MultiJvm" because the
display logic was guessing the identifier by capitalizing the ivy
config name.
**Solution**
This fix:
- Adds configNameToIdent reverse mapping in ConfigIndex to look up
the correct Configuration.id from the ivy config name
- Adds toConfigIdent method in KeyIndex trait for display lookup
- Updates Scope.display to accept a config name lookup function
- Updates showLoadingKey and showContextKey to use the index lookup
Fixes#5211
Generated-by: Claude
Add a rootProject convenience macro that expands to a Project with base "."
and the enclosing val name as id. Allows writing `val root = rootProject`
instead of `val root = (project in file("."))` for a stable root project id.
When using `ProjectMatrix` with `CrossVersion.full` and Scala 2 versions like `2.13.18`, the project ID incorrectly became `$1$2_13_18` instead of `foo2_13_18`.
**Root cause:** The Scala 3 compiler creates synthetic intermediate vals (e.g., `$1`) during macro expansion. The `enclosingTerm` function in the macros was stopping at these synthetic symbols instead of continuing up the symbol tree to find the actual val name.
**Fix:** Added `Flags.Synthetic` check to skip compiler-generated symbols in:
- `main-settings/src/main/scala/sbt/std/KeyMacro.scala`
- `lm-core/src/main/scala/sbt/librarymanagement/ConfigurationExtra.scala`
---------
Co-authored-by: byteforge38 <joseph.mc0803@gmail.com>
**Problem**
There's a disconnect between what is perceived to be the current
Scala version, and what sbt uses internally, and thus what it
chooses to be the default scalaVersion.
**Solution**
This displays a warning if scalaVersion setting is missing.
**Problem**
sha256 is currently a bottleneck for no-op compilation.
**Solution**
This adds a local, in-memory cache of sha256 hashes of binary files
using their timestamp and file size.
The size of the digest cache can be configured using localDigestCacheByteSize,
which is set to 1MB by default.
**Problem**
For sbt 1.x, the user is forced to pick between having a stable ID for the root project,
or having the automatic aggregation of all subprojects.
The problem becomes more pronounced for large build that frequent add/remove subprojects.
**Solution**
This implements `.autoAggregate` method on `Project`, which is implemented as
`this.aggregate(LocalAggregate)`.
At the loading time, we can automatically expand `LocalAggregate` to a list of subproject references,
after we discover all subprojects.
The `autoAggregate` will use the base directory of the subproject to pick the parent-child
relationship. For example, a root project would aggregate all subprojects,
but `bar` might aggregate only `bar/bar1` and `bar/bar2`.
**Problem**
test task is typed to unit.
To distinguish test from any other tasks, we want to actually type this to something.
**Solution**
Forward TestResult to the test task.
This flips the default `:=` operation to the cached task.
To opt out of the cache, use `Def.uncached(...)` or
mark the key with `@cacheLevel(include = Array.empty)`
**Problem**
Slash syntax is currently implemented via a series of implicit
converters (Conversion), which is not nice, partly because
the behavior is difficult to follow.
**Solution**
This removes all the implicit converters and moves the slashes
into:
1. / methods under Reference for subproject scoping.
2. / methods under ScopeAxis with Reference type constraint
for the initial Zero scoping.
3. Return RefThenConfig structure for intermediate config scoping.
4. / method under `Scoped`, which is base trait for the keys
to implement task scoping e.g. `compile / scalacOptions`.
5. Extension methods for ConfigKey.
6. Extension methods for AttributeKey.