diff --git a/backend/src/main/scala/bloop/Compiler.scala b/backend/src/main/scala/bloop/Compiler.scala index 868635248..49e366df9 100644 --- a/backend/src/main/scala/bloop/Compiler.scala +++ b/backend/src/main/scala/bloop/Compiler.scala @@ -873,9 +873,19 @@ object Compiler { case Array("-release", "8") => true case _ => false } - val updatedClasspath = - if (needsRtJar) inputs.classpath ++ RtJarCache.create(JavaRuntime.version, logger) - else inputs.classpath + val possibleRtJar = + if (needsRtJar) + inputs.javacBin + .flatMap { binary => + Try { + val javaHome = binary.getParent.getParent + javaHome.resolve("jre/lib/rt.jar") + }.toOption + } + .filter(_.exists) + .orElse(RtJarCache.create(JavaRuntime.version, logger)) + else None + val updatedClasspath = inputs.classpath ++ possibleRtJar val classpathVirtual = updatedClasspath.map(path => converter.toVirtualFile(path.underlying)) CompileOptions .create() diff --git a/frontend/src/test/scala/bloop/JavaVersionSpec.scala b/frontend/src/test/scala/bloop/JavaVersionSpec.scala index 8aa2a05cb..8af12c997 100644 --- a/frontend/src/test/scala/bloop/JavaVersionSpec.scala +++ b/frontend/src/test/scala/bloop/JavaVersionSpec.scala @@ -11,7 +11,7 @@ object JavaVersionSpec extends bloop.testing.BaseSuite { private val jvmManager = coursierapi.JvmManager.create() - def checkFlag(scalacOpts: List[String], jdkVersion: String = "8") = { + def checkFlag(scalacOpts: List[String], jdkVersion: String = "8", shouldFail: Boolean = false) = { val javaHome = jvmManager.get(jdkVersion).toPath() val jvmConfig = Some(Config.JvmConfig(Some(javaHome), Nil)) TestUtil.withinWorkspace { workspace => @@ -29,7 +29,7 @@ object JavaVersionSpec extends bloop.testing.BaseSuite { val projects = List(`A`) val state = loadState(workspace, projects, logger) val compiledState = state.compile(`A`) - if (jdkVersion == "8") { + if (jdkVersion == "8" || shouldFail) { assertExitStatus(compiledState, ExitStatus.CompilationError) val targetFoo = TestUtil.universalPath("a/src/main/scala/Foo.scala") assertNoDiff( @@ -63,7 +63,84 @@ object JavaVersionSpec extends bloop.testing.BaseSuite { checkFlag(Nil, jdkVersion = "11") } + test("doesnt-compile-with-11") { + checkFlag(List("-release", "8"), jdkVersion = "11", shouldFail = true) + checkFlag(List("-release:8"), jdkVersion = "11", shouldFail = true) + } + test("compiles-with-17") { checkFlag(Nil, jdkVersion = "17") } + + test("doesnt-compile-with-17") { + checkFlag(List("-release", "8"), jdkVersion = "17", shouldFail = true) + checkFlag(List("-release:8"), jdkVersion = "17", shouldFail = true) + } + + def checkRtJar(jdkVersion: String, scalacOpts: List[String] = Nil) = { + val javaHome = jvmManager.get(jdkVersion).toPath() + val jvmConfig = Some(Config.JvmConfig(Some(javaHome), Nil)) + TestUtil.withinWorkspace { workspace => + val sources = List( + """/main/scala/Foo.scala + |import java.net.http.HttpClient + |class Foo{ + | val output: HttpClient = ??? + |} + """.stripMargin + ) + + val logger = new RecordingLogger(ansiCodesSupported = false) + val `A` = + TestProject(workspace, "a", sources, jvmConfig = jvmConfig, scalacOptions = scalacOpts) + val projects = List(`A`) + val state = loadState(workspace, projects, logger) + val compiledState = state.compile(`A`) + if (jdkVersion == "8") { + assertExitStatus(compiledState, ExitStatus.CompilationError) + val targetFoo = TestUtil.universalPath("a/src/main/scala/Foo.scala") + assertNoDiff( + logger.renderErrors(), + s"""|[E2] $targetFoo:3:15 + | not found: type HttpClient + | L3: val output: HttpClient = ??? + | ^ + |[E1] $targetFoo:1:17 + | object http is not a member of package java.net + | L1: import java.net.http.HttpClient + | ^ + |$targetFoo: L1 [E1], L3 [E2] + |Failed to compile 'a' + |""".stripMargin + ) + } else { + assertExitStatus(compiledState, ExitStatus.Ok) + } + } + } + + if (!CrossPlatform.isM1) { + test("doesnt-compile") { + checkRtJar(jdkVersion = "8") + } + } + + test("compiles-11") { + checkRtJar(jdkVersion = "11") + + } + + test("compiles-17") { + checkRtJar(jdkVersion = "17") + } + + /* Current limitation: this should fail but the generated rt.jar contains all JDK 11 classes. + * However, most tools generating json configuration will set proper javaHome with JDK 8. + * Only if a user sets the flags themselves this will wrongly compile classes coming + * from future JDKs (but not added APIs). + */ + test("compiles-wrongly") { + checkRtJar(jdkVersion = "11", List("-release", "8")) + checkRtJar(jdkVersion = "17", List("-release", "8")) + } }