diff options
author | Lukas Rytz <lukas.rytz@epfl.ch> | 2010-08-03 20:03:08 +0000 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@epfl.ch> | 2010-08-03 20:03:08 +0000 |
commit | db99926628a2b636a548049c1204fee78c77b9bb (patch) | |
tree | 88122a98135c3c2165ad6364819a66854d61ec16 | |
parent | 958fb1c6f48aeecf5fc56ad9debbfad8d6d0fc66 (diff) | |
download | scala-db99926628a2b636a548049c1204fee78c77b9bb.tar.gz scala-db99926628a2b636a548049c1204fee78c77b9bb.tar.bz2 scala-db99926628a2b636a548049c1204fee78c77b9bb.zip |
added @deprecatedName annotation, allowing to d...
added @deprecatedName annotation, allowing to deprecate parameter names.
review by prokopec.
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Definitions.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Infer.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala | 31 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 10 | ||||
-rw-r--r-- | src/library/scala/deprecatedName.scala | 13 | ||||
-rw-r--r-- | test/files/neg/names-defaults-neg-warn.check | 7 | ||||
-rw-r--r-- | test/files/neg/names-defaults-neg-warn.flags | 1 | ||||
-rw-r--r-- | test/files/neg/names-defaults-neg-warn.scala | 14 | ||||
-rw-r--r-- | test/files/neg/names-defaults-neg.check | 23 | ||||
-rw-r--r-- | test/files/neg/names-defaults-neg.scala | 7 | ||||
-rw-r--r-- | test/files/run/names-defaults.check | 3 | ||||
-rw-r--r-- | test/files/run/names-defaults.scala | 16 |
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) |