summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/settings/MutableSettings.scala26
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala7
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Unapplies.scala25
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala1
-rw-r--r--test/files/run/t6541-option.scala19
-rw-r--r--test/files/run/t6541.flags1
-rw-r--r--test/files/run/t6541.scala25
-rw-r--r--test/files/run/xMigration.check49
-rw-r--r--test/files/run/xMigration.scala19
-rw-r--r--test/junit/scala/tools/nsc/settings/SettingsTest.scala16
10 files changed, 170 insertions, 18 deletions
diff --git a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
index 23611bb629..b4987e1240 100644
--- a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
@@ -229,7 +229,8 @@ class MutableSettings(val errorFn: String => Unit)
def OutputSetting(outputDirs: OutputDirs, default: String) = add(new OutputSetting(outputDirs, default))
def PhasesSetting(name: String, descr: String, default: String = "") = add(new PhasesSetting(name, descr, default))
def StringSetting(name: String, arg: String, descr: String, default: String) = add(new StringSetting(name, arg, descr, default))
- def ScalaVersionSetting(name: String, arg: String, descr: String, default: ScalaVersion) = add(new ScalaVersionSetting(name, arg, descr, default))
+ def ScalaVersionSetting(name: String, arg: String, descr: String, initial: ScalaVersion, default: Option[ScalaVersion] = None) =
+ add(new ScalaVersionSetting(name, arg, descr, initial, default))
def PathSetting(name: String, descr: String, default: String): PathSetting = {
val prepend = StringSetting(name + "/p", "", "", "").internalOnly()
val append = StringSetting(name + "/a", "", "", "").internalOnly()
@@ -506,28 +507,35 @@ class MutableSettings(val errorFn: String => Unit)
withHelpSyntax(name + " <" + arg + ">")
}
- /** A setting represented by a Scala version, (`default` unless set) */
+ /** A setting represented by a Scala version.
+ * The `initial` value is used if the setting is not specified.
+ * The `default` value is used if the option is specified without argument (e.g., `-Xmigration`).
+ */
class ScalaVersionSetting private[nsc](
name: String,
val arg: String,
descr: String,
- default: ScalaVersion)
+ initial: ScalaVersion,
+ default: Option[ScalaVersion])
extends Setting(name, descr) {
type T = ScalaVersion
- protected var v: T = NoScalaVersion
+ protected var v: T = initial
+ // This method is invoked if there are no colonated args. In this case the default value is
+ // used. No arguments are consumed.
override def tryToSet(args: List[String]) = {
- value = default
+ default match {
+ case Some(d) => value = d
+ case None => errorFn(s"$name requires an argument, the syntax is $helpSyntax")
+ }
Some(args)
}
override def tryToSetColon(args: List[String]) = args match {
- case Nil => value = default; Some(Nil)
- case x :: xs => value = ScalaVersion(x, errorFn) ; Some(xs)
+ case x :: xs => value = ScalaVersion(x, errorFn); Some(xs)
+ case nil => Some(nil)
}
- override def tryToSetFromPropertyValue(s: String) = tryToSet(List(s))
-
def unparse: List[String] = if (value == NoScalaVersion) Nil else List(s"${name}:${value.unparse}")
withHelpSyntax(s"${name}:<${arg}>")
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index 850534f2cc..c59d56d8f8 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -92,7 +92,8 @@ trait ScalaSettings extends AbsScalaSettings
* The previous "-source" option is intended to be used mainly
* though this helper.
*/
- lazy val isScala211: Boolean = (source.value >= ScalaVersion("2.11.0"))
+ def isScala211: Boolean = source.value >= ScalaVersion("2.11.0")
+ def isScala212: Boolean = source.value >= ScalaVersion("2.12.0")
/**
* -X "Advanced" settings
@@ -111,7 +112,7 @@ trait ScalaSettings extends AbsScalaSettings
val logFreeTerms = BooleanSetting ("-Xlog-free-terms", "Print a message when reification creates a free term.")
val logFreeTypes = BooleanSetting ("-Xlog-free-types", "Print a message when reification resorts to generating a free type.")
val maxClassfileName = IntSetting ("-Xmax-classfile-name", "Maximum filename length for generated classes", 255, Some((72, 255)), _ => None)
- val Xmigration = ScalaVersionSetting ("-Xmigration", "version", "Warn about constructs whose behavior may have changed since version.", AnyScalaVersion)
+ val Xmigration = ScalaVersionSetting ("-Xmigration", "version", "Warn about constructs whose behavior may have changed since version.", initial = NoScalaVersion, default = Some(AnyScalaVersion))
val nouescape = BooleanSetting ("-Xno-uescape", "Disable handling of \\u unicode escapes.")
val Xnojline = BooleanSetting ("-Xnojline", "Do not use JLine for editing.")
val Xverify = BooleanSetting ("-Xverify", "Verify generic signatures in generated bytecode (asm backend only.)")
@@ -133,7 +134,7 @@ trait ScalaSettings extends AbsScalaSettings
val showPhases = BooleanSetting ("-Xshow-phases", "Print a synopsis of compiler phases.")
val sourceReader = StringSetting ("-Xsource-reader", "classname", "Specify a custom method for reading source files.", "")
val strictInference = BooleanSetting ("-Xstrict-inference", "Don't infer known-unsound types")
- val source = ScalaVersionSetting ("-Xsource", "version", "Treat compiler input as Scala source for the specified version, see SI-8126.", ScalaVersion("2.11")) withPostSetHook ( _ => isScala211)
+ val source = ScalaVersionSetting ("-Xsource", "version", "Treat compiler input as Scala source for the specified version, see SI-8126.", initial = ScalaVersion("2.11"))
val XnoPatmatAnalysis = BooleanSetting ("-Xno-patmat-analysis", "Don't perform exhaustivity/unreachability analysis. Also, ignore @switch annotation.")
val XfullLubs = BooleanSetting ("-Xfull-lubs", "Retains pre 2.10 behavior of less aggressive truncation of least upper bounds.")
diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
index cc2d9141ce..fc1f45e358 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
@@ -142,17 +142,30 @@ trait Unapplies extends ast.TreeDSL {
/** The unapply method corresponding to a case class
*/
def caseModuleUnapplyMeth(cdef: ClassDef): DefDef = {
- val tparams = constrTparamsInvariant(cdef)
- val method = constrParamss(cdef) match {
+ val tparams = constrTparamsInvariant(cdef)
+ val method = constrParamss(cdef) match {
case xs :: _ if xs.nonEmpty && isRepeatedParamType(xs.last.tpt) => nme.unapplySeq
case _ => nme.unapply
}
- val cparams = List(ValDef(Modifiers(PARAM | SYNTHETIC), unapplyParamName, classType(cdef, tparams), EmptyTree))
- val ifNull = if (constrParamss(cdef).head.isEmpty) FALSE else REF(NoneModule)
- val body = nullSafe({ case Ident(x) => caseClassUnapplyReturnValue(x, cdef) }, ifNull)(Ident(unapplyParamName))
+ val cparams = List(ValDef(Modifiers(PARAM | SYNTHETIC), unapplyParamName, classType(cdef, tparams), EmptyTree))
+ val resultType = if (!settings.isScala212) TypeTree() else { // fix for SI-6541 under -Xsource:2.12
+ def repeatedToSeq(tp: Tree) = tp match {
+ case AppliedTypeTree(Select(_, tpnme.REPEATED_PARAM_CLASS_NAME), tps) => AppliedTypeTree(gen.rootScalaDot(tpnme.Seq), tps)
+ case _ => tp
+ }
+ constrParamss(cdef) match {
+ case Nil | Nil :: _ =>
+ gen.rootScalaDot(tpnme.Boolean)
+ case params :: _ =>
+ val constrParamTypes = params.map(param => repeatedToSeq(param.tpt))
+ AppliedTypeTree(gen.rootScalaDot(tpnme.Option), List(treeBuilder.makeTupleType(constrParamTypes)))
+ }
+ }
+ val ifNull = if (constrParamss(cdef).head.isEmpty) FALSE else REF(NoneModule)
+ val body = nullSafe({ case Ident(x) => caseClassUnapplyReturnValue(x, cdef) }, ifNull)(Ident(unapplyParamName))
atPos(cdef.pos.focus)(
- DefDef(caseMods, method, tparams, List(cparams), TypeTree(), body)
+ DefDef(caseMods, method, tparams, List(cparams), resultType, body)
)
}
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index 99ff6a10b4..f2517fff54 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -128,6 +128,7 @@ trait StdNames {
final val AnyRef: NameType = "AnyRef"
final val Array: NameType = "Array"
final val List: NameType = "List"
+ final val Option: NameType = "Option"
final val Seq: NameType = "Seq"
final val Symbol: NameType = "Symbol"
final val WeakTypeTag: NameType = "WeakTypeTag"
diff --git a/test/files/run/t6541-option.scala b/test/files/run/t6541-option.scala
new file mode 100644
index 0000000000..2c10c9e09d
--- /dev/null
+++ b/test/files/run/t6541-option.scala
@@ -0,0 +1,19 @@
+import scala.tools.partest.ReplTest
+
+object Test extends ReplTest {
+ def code = """
+:setting -Xsource:2.12
+case class C12(clazz: Class[_])
+val o: Option[Class[T] forSome { type T}] = C12.unapply(C12(classOf[String]))
+
+:setting -Xsource:2.11
+import scala.language.existentials
+case class C11(clazz: Class[_])
+val o: Option[Class[T]] forSome { type T } = C11.unapply(C11(classOf[String]))
+ """
+
+ override def show() = {
+ val r = eval().mkString("\n")
+ assert(!(r.contains("warning") || r.contains("error")), r)
+ }
+}
diff --git a/test/files/run/t6541.flags b/test/files/run/t6541.flags
new file mode 100644
index 0000000000..68d0ddfec2
--- /dev/null
+++ b/test/files/run/t6541.flags
@@ -0,0 +1 @@
+-feature -Xfatal-warnings -Xsource:2.12 \ No newline at end of file
diff --git a/test/files/run/t6541.scala b/test/files/run/t6541.scala
new file mode 100644
index 0000000000..f127143691
--- /dev/null
+++ b/test/files/run/t6541.scala
@@ -0,0 +1,25 @@
+class A
+class B[T](x: T)
+case class C(a: A, b: B[_])
+
+case class D(a: A, b: B[_]*)
+
+case class E(c: Class[_])
+
+object Test extends App {
+ def f1(c: C) = c match {
+ case C(a, b) => ()
+ }
+
+ def f2(d: D) = d match {
+ case D(a, b1, b2) => ()
+ }
+
+ def f3(e: E) = e match {
+ case E(c) => ()
+ }
+
+ f1(C(new A, new B(1)))
+ f2(D(new A, new B(1), new B(2)))
+ f3(E(classOf[E]))
+}
diff --git a/test/files/run/xMigration.check b/test/files/run/xMigration.check
new file mode 100644
index 0000000000..378f7bb6c3
--- /dev/null
+++ b/test/files/run/xMigration.check
@@ -0,0 +1,49 @@
+Type in expressions to have them evaluated.
+Type :help for more information.
+
+scala> Map(1 -> "eis").values // no warn
+res0: Iterable[String] = MapLike(eis)
+
+scala> :setting -Xmigration:none
+
+scala> Map(1 -> "eis").values // no warn
+res1: Iterable[String] = MapLike(eis)
+
+scala> :setting -Xmigration:any
+
+scala> Map(1 -> "eis").values // warn
+<console>:8: warning: method values in trait MapLike has changed semantics in version 2.8.0:
+`values` returns `Iterable[B]` rather than `Iterator[B]`.
+ Map(1 -> "eis").values // warn
+ ^
+res2: Iterable[String] = MapLike(eis)
+
+scala> :setting -Xmigration:2.8
+
+scala> Map(1 -> "eis").values // no warn
+res3: Iterable[String] = MapLike(eis)
+
+scala> :setting -Xmigration:2.7
+
+scala> Map(1 -> "eis").values // warn
+<console>:8: warning: method values in trait MapLike has changed semantics in version 2.8.0:
+`values` returns `Iterable[B]` rather than `Iterator[B]`.
+ Map(1 -> "eis").values // warn
+ ^
+res4: Iterable[String] = MapLike(eis)
+
+scala> :setting -Xmigration:2.11
+
+scala> Map(1 -> "eis").values // no warn
+res5: Iterable[String] = MapLike(eis)
+
+scala> :setting -Xmigration // same as :any
+
+scala> Map(1 -> "eis").values // warn
+<console>:8: warning: method values in trait MapLike has changed semantics in version 2.8.0:
+`values` returns `Iterable[B]` rather than `Iterator[B]`.
+ Map(1 -> "eis").values // warn
+ ^
+res6: Iterable[String] = MapLike(eis)
+
+scala> :quit
diff --git a/test/files/run/xMigration.scala b/test/files/run/xMigration.scala
new file mode 100644
index 0000000000..688e878397
--- /dev/null
+++ b/test/files/run/xMigration.scala
@@ -0,0 +1,19 @@
+import scala.tools.partest.ReplTest
+
+object Test extends ReplTest {
+ def code = """
+Map(1 -> "eis").values // no warn
+:setting -Xmigration:none
+Map(1 -> "eis").values // no warn
+:setting -Xmigration:any
+Map(1 -> "eis").values // warn
+:setting -Xmigration:2.8
+Map(1 -> "eis").values // no warn
+:setting -Xmigration:2.7
+Map(1 -> "eis").values // warn
+:setting -Xmigration:2.11
+Map(1 -> "eis").values // no warn
+:setting -Xmigration // same as :any
+Map(1 -> "eis").values // warn
+ """
+}
diff --git a/test/junit/scala/tools/nsc/settings/SettingsTest.scala b/test/junit/scala/tools/nsc/settings/SettingsTest.scala
index eda0c27834..96f83c4c2f 100644
--- a/test/junit/scala/tools/nsc/settings/SettingsTest.scala
+++ b/test/junit/scala/tools/nsc/settings/SettingsTest.scala
@@ -164,4 +164,20 @@ class SettingsTest {
assertThrows[IllegalArgumentException](check("-m:a,b,-ab")(_ => true), _ contains "'ab' cannot be negated")
assertThrows[IllegalArgumentException](check("-m:a,ac,-uber,uber")(_ => true), _ contains "'uber' cannot be negated")
}
+
+ @Test def xSourceTest(): Unit = {
+ def check(expected: String, args: String*): Unit = {
+ val s = new MutableSettings(msg => throw new IllegalArgumentException(msg))
+ val (_, residual) = s.processArguments(args.toList, processAll = true)
+ assert(residual.isEmpty)
+ assertTrue(s.source.value == ScalaVersion(expected))
+ }
+ check(expected = "2.11.0") // default
+ check(expected = "2.11.0", "-Xsource:2.11")
+ check(expected = "2.10", "-Xsource:2.10.0")
+ check(expected = "2.12", "-Xsource:2.12")
+ assertThrows[IllegalArgumentException](check(expected = "2.11", "-Xsource"), _ == "-Xsource requires an argument, the syntax is -Xsource:<version>")
+ assertThrows[IllegalArgumentException](check(expected = "2.11", "-Xsource", "2.11"), _ == "-Xsource requires an argument, the syntax is -Xsource:<version>")
+ assertThrows[IllegalArgumentException](check(expected = "2.11", "-Xsource:2.invalid"), _ contains "There was a problem parsing 2.invalid")
+ }
}