[2.x] fix: Fixes subproject deps with different Scala versions (#8681)

When a project depended on another project that was built with a different Scala binary version (e.g. 2.12 vs 2.13), compilation could fail with "not found: value X" because resolution was asking for the wrong artifact.

This change updates how we build the `ModuleID` for inter-project dependencies in `projectDependenciesTask`: we now request the dependency’s Scala binary version (e.g. `bar_2.12`) instead of the current project’s, so the resolver can find the right artifact. We keep existing behavior for `Disabled` and `Constant` cross-version, and add a small safeguard in the default case when the dependency’s Scala version differs from the current project’s.
This commit is contained in:
bitloi 2026-02-03 13:40:00 -05:00 committed by GitHub
parent 5ba750059c
commit b0601b4c6c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 63 additions and 2 deletions

View File

@ -4230,9 +4230,34 @@ object Classpaths {
.withCrossVersion(CrossVersion.constant(b.prefix + depSBV))
.withConfigurations(dep.configuration)
.withExplicitArtifacts(Vector.empty)
case _ if depAuto && VirtualAxis.isScala2Scala3Sandwich(sbv, depSBV) =>
case b: CrossVersion.Binary if sbv != depSBV =>
depProjId
.withCrossVersion(CrossVersion.constant(depSBV))
.withCrossVersion(CrossVersion.constant(b.prefix + depSBV + b.suffix))
.withConfigurations(dep.configuration)
.withExplicitArtifacts(Vector.empty)
case f: CrossVersion.Full if sbv != depSBV =>
val cross = (dep.project / scalaVersion)
.get(data)
.map(sv => CrossVersion.constant(f.prefix + sv + f.suffix))
.getOrElse(depProjId.crossVersion)
depProjId
.withCrossVersion(cross)
.withConfigurations(dep.configuration)
.withExplicitArtifacts(Vector.empty)
// For3Use2_13/For2_13Use3 publish under compat suffix (e.g. bar_2.13 on Scala 3),
// not raw depSBV; sandwich case uses constant(depSBV) so would request wrong artifact.
case c: sbt.librarymanagement.For3Use2_13 if sbv != depSBV =>
val compat =
if (depSBV == "3" || depSBV.startsWith("3.0.0")) "2.13"
else depSBV
depProjId
.withCrossVersion(CrossVersion.constant(c.prefix + compat + c.suffix))
.withConfigurations(dep.configuration)
.withExplicitArtifacts(Vector.empty)
case c: sbt.librarymanagement.For2_13Use3 if sbv != depSBV =>
val compat = if (depSBV == "2.13") "3" else depSBV
depProjId
.withCrossVersion(CrossVersion.constant(c.prefix + compat + c.suffix))
.withConfigurations(dep.configuration)
.withExplicitArtifacts(Vector.empty)
case _ =>

View File

@ -0,0 +1,3 @@
object Bar {
def value: String = "from-bar-2.12"
}

View File

@ -0,0 +1,9 @@
import java.nio.file.Files
import java.nio.file.Paths
object Main {
def main(args: Array[String]): Unit = {
val msg = Bar.value
Files.write(Paths.get("baz/output"), msg.getBytes("UTF-8"))
}
}

View File

@ -0,0 +1,19 @@
// sbt#4847: inter-project deps with variant Scala binary versions.
// bar uses 2.12, baz uses 2.13; baz dependsOn(bar). Resolution must ask for bar_2.12, not bar_2.13.
ThisBuild / organization := "com.example"
ThisBuild / version := "0.1.0-SNAPSHOT"
lazy val foo = project in file(".")
aggregateProjects(bar, baz)
lazy val bar = project.settings(
scalaVersion := "2.12.18",
name := "bar",
)
lazy val baz = project
.dependsOn(bar)
.settings(
scalaVersion := "2.13.12",
name := "baz",
)

View File

@ -0,0 +1,5 @@
# sbt#4847: baz (2.13) dependsOn bar (2.12); update must resolve bar_2.12, then baz/run must succeed.
$ delete baz/output
> baz/update
> baz/run
$ exists baz/output