summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala31
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala10
-rw-r--r--src/library/scala/deprecatedName.scala13
-rw-r--r--test/files/neg/names-defaults-neg-warn.check7
-rw-r--r--test/files/neg/names-defaults-neg-warn.flags1
-rw-r--r--test/files/neg/names-defaults-neg-warn.scala14
-rw-r--r--test/files/neg/names-defaults-neg.check23
-rw-r--r--test/files/neg/names-defaults-neg.scala7
-rw-r--r--test/files/run/names-defaults.check3
-rw-r--r--test/files/run/names-defaults.scala16
12 files changed, 122 insertions, 7 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
index 1684b5f071..667bdd5386 100644
--- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
@@ -136,6 +136,7 @@ trait Definitions extends reflect.generic.StandardDefinitions {
lazy val ScalaObjectClass = getClass("scala.ScalaObject")
lazy val PartialFunctionClass = getClass("scala.PartialFunction")
lazy val SymbolClass = getClass("scala.Symbol")
+ lazy val Symbol_apply = getMember(SymbolClass.companionModule, nme.apply)
lazy val StringClass = getClass(sn.String)
lazy val ClassClass = getClass(sn.Class)
def Class_getMethod = getMember(ClassClass, nme.getMethod_)
@@ -445,6 +446,7 @@ trait Definitions extends reflect.generic.StandardDefinitions {
// special attributes
lazy val SerializableAttr: Symbol = getClass("scala.serializable")
lazy val DeprecatedAttr: Symbol = getClass("scala.deprecated")
+ lazy val DeprecatedNameAttr: Symbol = getClass("scala.deprecatedName")
lazy val MigrationAnnotationClass: Symbol = getClass("scala.annotation.migration")
lazy val BeanPropertyAttr: Symbol = getClass(sn.BeanProperty)
lazy val BooleanBeanPropertyAttr: Symbol = getClass(sn.BooleanBeanProperty)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index ed5f3b0e9a..71c4353834 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -694,7 +694,7 @@ trait Infer {
val argtpes1 = argtpes map {
case NamedType(name, tp) => // a named argument
var res = tp
- val pos = params.indexWhere(p => p.name == name && !p.hasFlag(SYNTHETIC))
+ val pos = params.indexWhere(p => (p.name == name || deprecatedName(p) == Some(name)) && !p.hasFlag(SYNTHETIC))
if (pos == -1) {
if (positionalAllowed) { // treat assignment as positional argument
argPos(index) = index
diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
index 91fe113019..d783cf9c9f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
@@ -410,7 +410,10 @@ trait NamesDefaults { self: Analyzer =>
var positionalAllowed = true
val namelessArgs = for ((arg, index) <- (args.zipWithIndex)) yield arg match {
case a @ AssignOrNamedArg(Ident(name), rhs) =>
- val pos = params.indexWhere(p => p.name == name && !p.hasFlag(SYNTHETIC))
+ val (pos, newName) = paramPos(params, name)
+ newName.foreach(n => {
+ typer.context.unit.deprecationWarning(arg.pos, "the parameter name "+ name +" has been deprecated. Use "+ n +" instead.")
+ })
if (pos == -1) {
if (positionalAllowed) {
argPos(index) = index
@@ -482,4 +485,30 @@ trait NamesDefaults { self: Analyzer =>
res = context.lookup(clazz.name.toTermName, clazz.owner)
res
}
+
+ /**
+ * Returns
+ * - the position of the parameter named `name`
+ * - optionally, if `name` is @deprecatedName, the new name
+ */
+ def paramPos(params: List[Symbol], name: Name): (Int, Option[Name]) = {
+ var i = 0
+ var rest = params
+ while (!rest.isEmpty) {
+ val p = rest.head
+ if (!p.hasFlag(SYNTHETIC)) {
+ if (p.name == name) return (i, None)
+ if (deprecatedName(p) == Some(name)) return (i, Some(p.name))
+ }
+ i += 1
+ rest = rest.tail
+ }
+ (-1, None)
+ }
+
+ def deprecatedName(sym: Symbol): Option[Name] =
+ sym.getAnnotation(DeprecatedNameAttr).map(ann => (ann.args(0): @unchecked) match {
+ case Apply(fun, Literal(str) :: Nil) if (fun.symbol == Symbol_apply) =>
+ newTermName(str.stringValue)
+ })
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 043c41fc10..770daccef0 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1758,6 +1758,16 @@ trait Typers { self: Analyzer =>
meth.paramss.exists(ps => ps.exists(_.hasFlag(DEFAULTPARAM)) && isRepeatedParamType(ps.last.tpe)))
error(meth.pos, "a parameter section with a `*'-parameter is not allowed to have default arguments")
+ if (phase.id <= currentRun.typerPhase.id) {
+ val allParams = meth.paramss.flatten
+ for (p <- allParams) {
+ deprecatedName(p).foreach(n => {
+ if (allParams.exists(p1 => p1.name == n || (p != p1 && deprecatedName(p1) == Some(n))))
+ error(p.pos, "deprecated parameter name "+ n +" has to be distinct from any other parameter name (deprecated or not).")
+ })
+ }
+ }
+
checkMethodStructuralCompatible(meth)
treeCopy.DefDef(ddef, typedMods, ddef.name, tparams1, vparamss1, tpt1, rhs1) setType NoType
diff --git a/src/library/scala/deprecatedName.scala b/src/library/scala/deprecatedName.scala
new file mode 100644
index 0000000000..30d0ae457a
--- /dev/null
+++ b/src/library/scala/deprecatedName.scala
@@ -0,0 +1,13 @@
+package scala
+
+import annotation.target._
+
+/**
+ * An annotation that designates the name of the parameter to which it is
+ * applied as deprecated. Using that name in a named argument generates
+ * a deprecation warning.
+ *
+ * @since 2.8.1
+ */
+@param
+class deprecatedName(name: Symbol) extends StaticAnnotation
diff --git a/test/files/neg/names-defaults-neg-warn.check b/test/files/neg/names-defaults-neg-warn.check
new file mode 100644
index 0000000000..e1085acf76
--- /dev/null
+++ b/test/files/neg/names-defaults-neg-warn.check
@@ -0,0 +1,7 @@
+names-defaults-neg-warn.scala:11: error: the parameter name s has been deprecated. Use x instead.
+ deprNam2.f(s = "dlfkj")
+ ^
+names-defaults-neg-warn.scala:12: error: the parameter name x has been deprecated. Use s instead.
+ deprNam2.g(x = "dlkjf")
+ ^
+two errors found
diff --git a/test/files/neg/names-defaults-neg-warn.flags b/test/files/neg/names-defaults-neg-warn.flags
new file mode 100644
index 0000000000..d1b831ea87
--- /dev/null
+++ b/test/files/neg/names-defaults-neg-warn.flags
@@ -0,0 +1 @@
+-deprecation -Xfatal-warnings \ No newline at end of file
diff --git a/test/files/neg/names-defaults-neg-warn.scala b/test/files/neg/names-defaults-neg-warn.scala
new file mode 100644
index 0000000000..7cb956cc86
--- /dev/null
+++ b/test/files/neg/names-defaults-neg-warn.scala
@@ -0,0 +1,14 @@
+object Test extends Application {
+ object deprNam2 {
+ def f(@deprecatedName('s) x: String) = 1
+ def f(s: Object) = 2
+
+ def g(@deprecatedName('x) s: Object) = 3
+ def g(s: String) = 4
+ }
+
+ deprNam2.f(s = new Object)
+ deprNam2.f(s = "dlfkj")
+ deprNam2.g(x = "dlkjf")
+ deprNam2.g(s = new Object)
+}
diff --git a/test/files/neg/names-defaults-neg.check b/test/files/neg/names-defaults-neg.check
index b2b00b7050..ec786c5e03 100644
--- a/test/files/neg/names-defaults-neg.check
+++ b/test/files/neg/names-defaults-neg.check
@@ -107,17 +107,30 @@ Error occurred in an application involving default arguments.
names-defaults-neg.scala:86: error: module extending its companion class cannot use default constructor arguments
object C extends C()
^
-names-defaults-neg.scala:120: error: reference to var2 is ambiguous; it is both, a parameter
+names-defaults-neg.scala:90: error: deprecated parameter name x has to be distinct from any other parameter name (deprecated or not).
+ def deprNam1(x: Int, @deprecatedName('x) y: String) = 0
+ ^
+names-defaults-neg.scala:91: error: deprecated parameter name a has to be distinct from any other parameter name (deprecated or not).
+ def deprNam2(a: String)(@deprecatedName('a) b: Int) = 1
+ ^
+names-defaults-neg.scala:93: warning: the parameter name y has been deprecated. Use b instead.
+ deprNam3(y = 10, b = 2)
+ ^
+names-defaults-neg.scala:93: error: parameter specified twice: b
+ deprNam3(y = 10, b = 2)
+ ^
+names-defaults-neg.scala:127: error: reference to var2 is ambiguous; it is both, a parameter
name of the method and the name of a variable currently in scope.
delay(var2 = 40)
^
-names-defaults-neg.scala:123: error: missing parameter type for expanded function ((x$1) => a = x$1)
+names-defaults-neg.scala:130: error: missing parameter type for expanded function ((x$1) => a = x$1)
val taf2: Int => Unit = testAnnFun(a = _, b = get("+"))
^
-names-defaults-neg.scala:124: error: parameter specified twice: a
+names-defaults-neg.scala:131: error: parameter specified twice: a
val taf3 = testAnnFun(b = _: String, a = get(8))
^
-names-defaults-neg.scala:125: error: wrong number of parameters; expected = 2
+names-defaults-neg.scala:132: error: wrong number of parameters; expected = 2
val taf4: (Int, String) => Unit = testAnnFun(_, b = _)
^
-29 errors found
+one warning found
+32 errors found
diff --git a/test/files/neg/names-defaults-neg.scala b/test/files/neg/names-defaults-neg.scala
index 43883540a0..8d1ec4ce96 100644
--- a/test/files/neg/names-defaults-neg.scala
+++ b/test/files/neg/names-defaults-neg.scala
@@ -86,6 +86,13 @@ object Test extends Application {
object C extends C()
}
+ // deprecated names
+ def deprNam1(x: Int, @deprecatedName('x) y: String) = 0
+ def deprNam2(a: String)(@deprecatedName('a) b: Int) = 1
+ def deprNam3(@deprecatedName('x) a: Int, @deprecatedName('y) b: Int) = a + b
+ deprNam3(y = 10, b = 2)
+
+
// DEFINITIONS
def test1(a: Int, b: String) = a +": "+ b
def test2(x: Unit) = println("test2")
diff --git a/test/files/run/names-defaults.check b/test/files/run/names-defaults.check
index b4effa26d2..5b271a5d28 100644
--- a/test/files/run/names-defaults.check
+++ b/test/files/run/names-defaults.check
@@ -106,3 +106,6 @@ blublu1
my text
List(1, 2)
3
+1
+2
+3
diff --git a/test/files/run/names-defaults.scala b/test/files/run/names-defaults.scala
index 8ddfcd950d..2a50d26cdd 100644
--- a/test/files/run/names-defaults.scala
+++ b/test/files/run/names-defaults.scala
@@ -350,6 +350,22 @@ object Test extends Application {
class DBLAH(val y: String = "2") extends CBLAH()
(new DBLAH())
+ // deprecated names
+ def deprNam1(@deprecatedName('x) a: Int, @deprecatedName('y) b: Int) = a + b
+ deprNam1(y = 10, a = 1)
+ deprNam1(b = 2, x = 10)
+
+ object deprNam2 {
+ def f(@deprecatedName('s) x: String) = 1
+ def f(s: Object) = 2
+
+ def g(@deprecatedName('x) s: Object) = 3
+ def g(s: String) = 4
+ }
+ println(deprNam2.f(s = "dlf"))
+ println(deprNam2.f(s = new Object))
+ println(deprNam2.g(x = "sljkfd"))
+
// DEFINITIONS
def test1(a: Int, b: String) = println(a +": "+ b)