diff --git a/modules/cli-options/src/main/scala/scala/cli/commands/ScalacOptions.scala b/modules/cli-options/src/main/scala/scala/cli/commands/ScalacOptions.scala index e22dcc119e..1711fd7ca2 100644 --- a/modules/cli-options/src/main/scala/scala/cli/commands/ScalacOptions.scala +++ b/modules/cli-options/src/main/scala/scala/cli/commands/ScalacOptions.scala @@ -35,7 +35,7 @@ object ScalacOptions { private val scalacOptionsPrefixes = Set("-g", "-language", "-opt", "-P", "-target") ++ scalacOptionsPurePrefixes private val scalacAliasedOptions = // these options don't require being passed after -O - Set("-encoding") + Set("-encoding", "-release") /** This includes all the scalac options which disregard inputs and print a help and/or context * message instead. @@ -46,7 +46,8 @@ object ScalacOptions { /** This includes all the scalac options which are redirected to native Scala CLI options. */ val ScalaCliRedirectedOptions = Set( "-classpath", // redirected to --extra-jars - "-d" // redirected to --compilation-output + "-d", // redirected to --compilation-output + "-release" // redirected to --jvm ) private val scalacOptionsArgument: Argument[List[String]] = diff --git a/modules/cli/src/main/scala/scala/cli/commands/util/JvmUtils.scala b/modules/cli/src/main/scala/scala/cli/commands/util/JvmUtils.scala index c2c8818145..cf3b896a39 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/util/JvmUtils.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/util/JvmUtils.scala @@ -4,13 +4,17 @@ package util import java.io.File import scala.build.EitherCps.{either, value} -import scala.build.errors.{BuildException, UnrecognizedDebugModeError} +import scala.build.errors.{AmbiguousJvmError, BuildException, UnrecognizedDebugModeError} import scala.build.options.{JavaOpt, JavaOptions, ShadowingSeq} import scala.build.{Os, Position, Positioned} +import scala.cli.commands.util.ScalacOptionsUtil.* import scala.util.Properties object JvmUtils { - def javaOptions(opts: SharedJvmOptions): Either[BuildException, JavaOptions] = either { + def javaOptions( + opts: SharedJvmOptions, + scalacOpts: List[String] = List.empty + ): Either[BuildException, JavaOptions] = either { import opts._ val (javacFilePlugins, javacPluginDeps) = @@ -44,11 +48,21 @@ object JvmUtils { Seq.empty } + val jvmIdOpt: Option[String] = value { + jvm -> scalacOpts.toScalacOptShadowingSeq.getScalacOption("-release") match { + case (Some(j1), Some(j2)) if j1 == j2 => Right(Some(j1)) + case (Some(j1), Some(j2)) => Left(AmbiguousJvmError(Seq(j1, j2))) + case (Some(j), _) => Right(Some(j)) + case (_, Some(j)) => Right(Some(j)) + case _ => Right(None) + } + } + JavaOptions( javaHomeOpt = javaHome.filter(_.nonEmpty).map(v => Positioned(Seq(Position.CommandLine("--java-home")), os.Path(v, Os.pwd)) ), - jvmIdOpt = jvm.filter(_.nonEmpty), + jvmIdOpt = jvmIdOpt.filter(_.nonEmpty), jvmIndexOpt = jvmIndex.filter(_.nonEmpty), jvmIndexOs = jvmIndexOs.map(_.trim).filter(_.nonEmpty), jvmIndexArch = jvmIndexArch.map(_.trim).filter(_.nonEmpty), diff --git a/modules/cli/src/main/scala/scala/cli/commands/util/SharedOptionsUtil.scala b/modules/cli/src/main/scala/scala/cli/commands/util/SharedOptionsUtil.scala index 46f96c4cb8..8f29a673c2 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/util/SharedOptionsUtil.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/util/SharedOptionsUtil.scala @@ -203,7 +203,7 @@ object SharedOptionsUtil extends CommandHelpers { ), scalaJsOptions = scalaJsOptions(js), scalaNativeOptions = scalaNativeOptions(native), - javaOptions = value(scala.cli.commands.util.JvmUtils.javaOptions(jvm)), + javaOptions = value(scala.cli.commands.util.JvmUtils.javaOptions(jvm, scalac.scalacOption)), internalDependencies = bo.InternalDependenciesOptions( addStubsDependencyOpt = addStubs, addRunnerDependencyOpt = runner diff --git a/modules/core/src/main/scala/scala/build/errors/AmbiguousJvmError.scala b/modules/core/src/main/scala/scala/build/errors/AmbiguousJvmError.scala new file mode 100644 index 0000000000..d26df037b1 --- /dev/null +++ b/modules/core/src/main/scala/scala/build/errors/AmbiguousJvmError.scala @@ -0,0 +1,5 @@ +package scala.build.errors + +case class AmbiguousJvmError(passedJVMs: Seq[String]) extends BuildException( + s"Ambiguous JVM, more than one JVM have been passed: ${passedJVMs.sorted.mkString(", ")}." + ) diff --git a/modules/integration/src/test/scala/scala/cli/integration/CompileTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/CompileTestDefinitions.scala index 7f6e5c2979..24674b2f9b 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/CompileTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/CompileTestDefinitions.scala @@ -242,25 +242,6 @@ abstract class CompileTestDefinitions(val scalaVersionOpt: Option[String]) ) } - test("Scala CLI should not infer scalac's--release if 'O --release' is passed".tag(jvmT)) { - scalaJvm11Project.fromRoot { root => - val res = os.proc( - TestUtil.cli, - "compile", - extraOptions, - "--jvm", - "11", - "-O", - "-release", - "-O", - "8", - "." - ).call(cwd = root, check = false, stderr = os.Pipe) - expect(res.exitCode != 0) - expect(res.err.text().contains("isEmpty is not a member")) - } - } - def compileToADifferentJvmThanBloops( bloopJvm: String, targetJvm: String, diff --git a/modules/integration/src/test/scala/scala/cli/integration/RunTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/RunTestDefinitions.scala index e083fab97a..1ffd84dfe0 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/RunTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/RunTestDefinitions.scala @@ -2555,4 +2555,40 @@ abstract class RunTestDefinitions(val scalaVersionOpt: Option[String]) expect(res.out.trim == "€") } } + + test("different jvm values passed to --jvm and -release should produce an error message") { + TestInputs(os.rel / "s.sc" -> """println("Hello")""") + .fromRoot { root => + val res = os.proc( + TestUtil.cli, + "s.sc", + "-release", + "8", + "--jvm", + "11", + extraOptions + ).call(cwd = root, check = false, stderr = os.Pipe) + val expectedError = + s"[${Console.RED}error${Console.RESET}] Ambiguous JVM, more than one JVM have been passed: 11, 8." + expect(res.err.trim == expectedError) + } + } + + test("-release allows to set the JVM on par with --jvm") { + val expectedMsg = "Hello" + TestInputs(os.rel / "s.sc" -> + s"""import java.net.http.HttpRequest + |println("$expectedMsg")""".stripMargin) + .fromRoot { root => + val res8 = os.proc(TestUtil.cli, "s.sc", "-release", "8", extraOptions) + .call(cwd = root, check = false, stderr = os.Pipe) + expect(res8.exitCode == 1) + val res8jvm = os.proc(TestUtil.cli, "s.sc", "--jvm", "8", extraOptions) + .call(cwd = root, check = false, stderr = os.Pipe) + expect(res8.err.trim == res8jvm.err.trim) + val res11 = os.proc(TestUtil.cli, "s.sc", "-release", "11", extraOptions) + .call(cwd = root) + expect(res11.out.trim == expectedMsg) + } + } }