10000 [backport] Make `-target` support JDK 8 through 19 (and deprecate 5 through 7) by stefan-jurco · Pull Request #9916 · scala/scala · GitHub
[go: up one dir, main page]

Skip to content

[backport] Make -target support JDK 8 through 19 (and deprecate 5 through 7) #9916

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weâ 10000 €™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion project/ScalaOptionParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ object ScalaOptionParser {
"-Ymacro-expand" -> List("discard", "none"),
"-Yresolve-term-conflict" -> List("error", "object", "package"),
"-g" -> List("line", "none", "notailcails", "source", "vars"),
"-target" -> List("jvm-1.5", "jvm-1.6", "jvm-1.7", "jvm-1.8"))
"-target" -> targetSettingNames)
private def multiChoiceSettingNames = Map[String, List[String]](
"-Xlint" -> List("adapted-args", "nullary-unit", "inaccessible", "nullary-override", "infer-any", "missing-interpolator", "doc-detached", "private-shadow", "type-parameter-shadow", "poly-implicit-overload", "option-implicit", "delayedinit-select", "by-name-right-associative", "package-object-classes", "unsound-match", "stars-align"),
"-language" -> List("help", "_", "dynamics", "postfixOps", "reflectiveCalls", "implicitConversions", "higherKinds", "existentials", "experimental.macros"),
Expand All @@ -126,4 +126,5 @@ object ScalaOptionParser {
private def scaladocPathSettingNames = List("-doc-root-content", "-diagrams-dot-path")
private def scaladocMultiStringSettingNames = List("-doc-external-doc")

private val targetSettingNames = (5 to 18).flatMap(v => s"$v" :: s"jvm-1.$v" :: s"jvm-$v" :: s"1.$v" :: Nil).toList
}
3 changes: 2 additions & 1 deletion src/compiler/scala/tools/ant/Scalac.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import org.apache.tools.ant.util.facade.{FacadeTaskHelper, ImplementationSpecifi
import scala.tools.nsc.{Global, Settings, CompilerCommand}
import scala.tools.nsc.io.{Path => SPath}
import scala.tools.nsc.reporters.{ ConsoleReporter, Reporter }
import scala.tools.nsc.settings.StandardScalaSettings

/** An Ant task to compile with the new Scala compiler (NSC).
*
Expand Down Expand Up @@ -99,7 +100,7 @@ class Scalac extends ScalaMatchingTask with ScalacShared {

/** Defines valid values for the `target` property. */
object Target extends PermissibleValue {
val values = List("jvm-1.5", "jvm-1.6", "jvm-1.7", "jvm-1.8")
val values = StandardScalaSettings.AllPermissibleTargetValues
}

/** Defines valid values for the `deprecation` and `unchecked` properties. */
Expand Down
14 changes: 10 additions & 4 deletions src/compiler/scala/tools/nsc/Global.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import scala.tools.nsc.io.{AbstractFile, SourceReader}
import scala.tools.nsc.plugins.Plugins
import scala.tools.nsc.profile.Profiler
import scala.tools.nsc.reporters.{FilteringReporter, MakeFilteringForwardingReporter, Reporter}
import scala.tools.nsc.settings.StandardScalaSettings
import scala.tools.nsc.symtab.classfile.Pickler
import scala.tools.nsc.symtab.{Flags, SymbolTable, SymbolTrackers}
import scala.tools.nsc.transform._
Expand Down Expand Up @@ -1368,10 +1369,15 @@ class Global(var currentSettings: Settings, reporter0: Reporter)
settings.userSetSettings filter (_.isDeprecated) foreach { s =>
runReporting.deprecationWarning(NoPosition, s.name + " is deprecated: " + s.deprecationMessage.get, "", "", "")
}
val supportedTarget = "jvm-1.8"
if (settings.target.value != supportedTarget) {
runReporting.deprecationWarning(NoPosition, settings.target.name + ":" + settings.target.value + " is deprecated and has no effect, setting to " + supportedTarget, "2.12.0", site = "", origin = "")
settings.target.value = supportedTarget
if (!StandardScalaSettings.SupportedTargetVersions.contains(settings.target.value)) {
runReporting.deprecationWarning(
NoPosition,
settings.target.name + ":" + settings.target.value + " is deprecated and has no effect, setting to " + StandardScalaSettings.DefaultTargetVersion,
since = "2.12.16",
site = "",
origin = ""
)
settings.target.value = StandardScalaSettings.DefaultTargetVersion
}
settings.conflictWarning.foreach(runReporting.warning(NoPosition, _, WarningCategory.Other, site = ""))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,19 @@ abstract class BackendUtils extends PerRunInit {
private[this] lazy val classesOfSideEffectFreeConstructors: LazyVar[Set[String]] = perRunLazy(this)(sideEffectFreeConstructors.get.map(_._1))

lazy val classfileVersion: LazyVar[Int] = perRunLazy(this)(compilerSettings.target match {
case "jvm-1.8" => asm.Opcodes.V1_8
})
case "8" => asm.Opcodes.V1_8
case "9" => asm.Opcodes.V9
case "10" => asm.Opcodes.V10
case "11" => asm.Opcodes.V11
case "12" => asm.Opcodes.V12
case "13" => asm.Opcodes.V13
case "14" => asm.Opcodes.V14
case "15" => asm.Opcodes.V15
case "16" => asm.Opcodes.V16
case "17" => asm.Opcodes.V17
case "18" => asm.Opcodes.V18
// to be continued...
})


lazy val majorVersion: LazyVar[Int] = perRunLazy(this)(classfileVersion.get & 0xFF)
Expand Down
9 changes: 6 additions & 3 deletions src/compiler/scala/tools/nsc/settings/MutableSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -230,9 +230,9 @@ class MutableSettings(val errorFn: String => Unit, val pathFactory: PathFactory)
def BooleanSetting(name: String, descr: String, default: Boolean = false) = add(new BooleanSetting(name, descr, default))
def ChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: String, choicesHelp: List[String] = Nil) =
add(new ChoiceSetting(name, helpArg, descr, choices, default, choicesHelp))
def ChoiceSettingForcedDefault(name: String, helpArg: String, descr: String, choices: List[String], default: String, choicesHelp: List[String] = Nil) =
def ChoiceSettingForcedDefault(name: String, helpArg: String, descr: String, choices: List[String], supported: List[String], default: String, choicesHelp: List[String] = Nil) =
ChoiceSetting(name, helpArg, descr, choices, default, choicesHelp).withPostSetHook(sett =>
if (sett.value != default) {
if (!supported.contains(sett.value)) {
sett.withDeprecationMessage(s"${name}:${sett.value} is deprecated, forcing use of $default")
sett.value = default
}
Expand Down Expand Up @@ -846,6 +846,9 @@ class MutableSettings(val errorFn: String => Unit, val pathFactory: PathFactory)
protected var v: T = default
def indexOfChoice: Int = choices indexOf value

private[this] var _preSetHook: String => String = s => s
def withPreSetHook(hook: String => String): this.type = { _preSetHook = hook ; this }

private def choicesHelpMessage = if (choicesHelp.isEmpty) "" else {
val choiceLength = choices.map(_.length).max + 1
val formatStr = s" %-${choiceLength}s %s%n"
Expand All @@ -861,7 +864,7 @@ class MutableSettings(val errorFn: String => Unit, val pathFactory: PathFactory)

def tryToSet(args: List[String]) = errorAndValue(usageErrorMessage, None)

override def tryToSetColon(args: List[String]) = args match {
override def tryToSetColon(args: List[String]) = args map _preSetHook match {
case Nil => errorAndValue(usageErrorMessage, None)
case List("help") => sawHelp = true; SomeOfNil
case List(x) if choices contains x => value = x ; SomeOfNil
Expand Down
22 changes: 20 additions & 2 deletions src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package scala.tools.nsc
package settings

import scala.tools.nsc.settings.StandardScalaSettings.{AllTargetVersions, DefaultTargetVersion, SupportedTargetVersions}
import scala.tools.util.PathResolver.Defaults

/** Settings which aren't behind a -X, -Y, or -P option.
Expand Down Expand Up @@ -54,8 +55,7 @@ trait StandardScalaSettings { _: MutableSettings =>
val nowarn = BooleanSetting ("-nowarn", "Generate no warnings.") withPostSetHook { s => if (s) maxwarns.value = 0 }
val optimise: BooleanSetting // depends on post hook which mutates other settings
val print = BooleanSetting ("-print", "Print program with Scala-specific features removed.")
val target = ChoiceSettingForcedDefault ("-target", "target", "Target platform for object files. All JVM 1.5 - 1.7 targets are deprecated.",
List("jvm-1.5", "jvm-1.6", "jvm-1.7", "jvm-1.8"), "jvm-1.8")
val target = ChoiceSettingForcedDefault ("-target", "target", "Target platform for object files. All JVM 1.5 - 1.7 targets are deprecated.", AllTargetVersions, SupportedTargetVersions, DefaultTargetVersion) withPreSetHook normalizeTarget
val unchecked = BooleanSetting ("-unchecked", "Enable additional warnings where generated code depends on assumptions. See also -Wconf.") withAbbreviation "--unchecked" withPostSetHook { s =>
if (s.value) Wconf.tryToSet(List(s"cat=unchecked:w"))
else Wconf.tryToSet(List(s"cat=unchecked:s"))
Expand All @@ -65,4 +65,22 @@ trait StandardScalaSettings { _: MutableSettings =>
val usemanifestcp = BooleanSetting ("-usemanifestcp", "Utilize the manifest in classpath resolution.")
val verbose = BooleanSetting ("-verbose", "Output messages about what the compiler is doing.")
val version = BooleanSetting ("-version", "Print product version and exit.")

// Support passe prefixes of -target values:
// - `jvm-` (from back when we also had `msil`)
// - `1.` (from back when Java 2 was a possibility)
// `-target:1.jvm-13` is ridiculous, though.
private[this] def normalizeTarget(in: String): String = in.stripPrefix("jvm-").stripPrefix("1.")
}

object StandardScalaSettings {
// not final in case some separately compiled client code wanted to depend on updated values
val MinTargetVersion = 5
val MinSupportedTargetVersion = 8
val MaxTargetVersion = 18
val DefaultTargetVersion = "8"

private val AllTargetVersions = (MinTargetVersion to MaxTargetVersion).map(_.toString).toList
val SupportedTargetVersions: List[String] = (MinSupportedTargetVersion to MaxTargetVersion).map(_.toString).toList
val AllPermissibleTargetValues: List[String] = AllTargetVersions.flatMap(v => v :: s"jvm-1.$v" :: s"jvm-$v" :: s"1.$v" :: Nil)
}
2 changes: 1 addition & 1 deletion test/files/neg/deprecated-target.check
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
warning: -target is deprecated: -target:jvm-1.7 is deprecated, forcing use of jvm-1.8
warning: -target is deprecated: -target:7 is deprecated, forcing use of 8
error: No warnings can be incurred under -Xfatal-warnings.
one warning found
one error found
95 changes: 95 additions & 0 deletions test/junit/scala/tools/nsc/settings/TargetTest.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Scala (https://www.scala-lang.org)
*
* Copyright EPFL and Lightbend, Inc.
*
* Licensed under Apache License 2.0
* (http://www.apache.org/licenses/LICENSE-2.0).
*
* See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*/

package scala.tools.nsc
package settings

import org.junit.{Assert, Test}, Assert.{assertEquals, assertFalse, assertTrue, fail}
import org.junit.runner.RunWith
import org.junit.runners.JUnit4

import scala.collection.mutable.ListBuffer

@RunWith(classOf[JUnit4])
class TargetTest {

@Test def testSettingTargetSetting(): Unit = {
def check(in: String, expect: String) = {
val settings = new Settings(err => fail(s"Error output: $err"))
val (ok, _) = settings.processArgumentString(in)
assertTrue(ok)
assertEquals(expect, settings.target.value)
}
def checkDeprecated(in: String, expect: String) = {
val messages = ListBuffer.empty[String]
val settings = new Settings(messages.append(_))
val (ok, _) = settings.processArgumentString(in)
assertTrue(ok)
assertTrue(messages.isEmpty)
assertTrue(settings.target.deprecationMessage.exists(_.contains("is deprecated, forcing use of")))
assertEquals(expect, settings.target.value)
}
def checkFail(in: String) = {
val messages = ListBuffer.empty[String]
val settings = new Settings(messages.append(_))
val (ok, _) = settings.processArgumentString(in)
assertFalse(ok)
assertTrue(messages.nonEmpty)
assertEquals(2, messages.size) // bad choice + bad option
assertTrue(messages.exists(_.startsWith("bad option")))
}

checkDeprecated("-target:jvm-1.5", "8")
checkDeprecated("-target:1.5", "8")

checkDeprecated("-target:jvm-1.6", "8")
checkDeprecated("-target:6", "8")

checkDeprecated("-target:jvm-1.7", "8")
checkDeprecated("-target:jvm-7", "8")

check("-target:jvm-1.8", "8")
check("-target:1.8", "8")
check("-target:jvm-8", "8")
check("-target:8", "8")

check("-target:jvm-9", "9")
check("-target:9", "9")
// it's not Java 1.9, you reprobates!

check("-target:jvm-10", "10")
check("-target:10", "10")

check("-target:jvm-11", "11")
check("-target:11", "11")

check("-target:jvm-12", "12")
check("-target:12", "12")

// (scene missing)

check("-target:jvm-16", "16")
check("-target:16", "16")

check("-target:jvm-17", "17")
check("-target:17", "17")

check("-target:jvm-18", "18")
check("-target:18", "18")

checkFail("-target:jvm-19") // not yet...
checkFail("-target:jvm-3000") // not in our lifetime
checkFail("-target:msil") // really?

}

}
0