From 40bef79974de3ed00f0173a65fdf7aa19170900e Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Sun, 29 Sep 2013 13:46:02 -0700 Subject: SI-9140 Allow deprecating current parameter name Allow deprecatedName to specify the name of the parameter it qualifies. This tells the user, That's my name, don't wear it out. I.e., don't use my name when calling me. Use cases include: the name will change; normally a name should be provided for a boolean, but not in this case (perhaps because there is only one argument). ``` scala> def f(@deprecatedName('foo) bar: String) = bar.reverse f: (bar: String)String scala> f(foo = "hello") :9: warning: the parameter name foo has been deprecated. Use bar instead. f(foo = "hello") ^ res0: String = olleh scala> def g(@deprecatedName('foo) foo: String) = foo.reverse g: (foo: String)String scala> g(foo = "hello") :9: warning: naming parameter foo has been deprecated. g(foo = "hello") ^ res1: String = olleh ``` --- test/files/neg/names-defaults-neg.scala | 2 ++ 1 file changed, 2 insertions(+) (limited to 'test/files/neg/names-defaults-neg.scala') diff --git a/test/files/neg/names-defaults-neg.scala b/test/files/neg/names-defaults-neg.scala index 042f73708c..d11c9910a1 100644 --- a/test/files/neg/names-defaults-neg.scala +++ b/test/files/neg/names-defaults-neg.scala @@ -92,6 +92,8 @@ object Test extends App { def deprNam3(@deprecatedName('x) a: Int, @deprecatedName('y) b: Int) = a + b deprNam3(y = 10, b = 2) + def deprNam4(@deprecatedName('deprNam4Arg) deprNam4Arg: String) = 0 + deprNam4(deprNam4Arg = null) // t3818 def f3818(x: Int = 1, y: Int, z: Int = 1) = 0 -- cgit v1.2.3 From e1c6f0eacd5372e5ee4fe267c6c5b7124cd162f3 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Mon, 9 Feb 2015 13:01:30 -0800 Subject: SI-9140 Allow omitting pleonastic parameter name Enable simply: ``` scala> def f(@deprecatedName foo: String) = foo.reverse f: (foo: String)String scala> f(foo = "bar") :9: warning: naming parameter foo has been deprecated. f(foo = "bar") ^ res0: String = rab ``` `Symbol.deprecatedParamName` conventionally returns `NO_NAME` when the name is omitted. --- .../tools/nsc/typechecker/NamesDefaults.scala | 10 +++-- src/library/scala/deprecatedName.scala | 4 +- src/reflect/scala/reflect/internal/Symbols.scala | 2 +- test/files/neg/names-defaults-neg.check | 45 ++++++++++++---------- test/files/neg/names-defaults-neg.scala | 2 + 5 files changed, 37 insertions(+), 26 deletions(-) (limited to 'test/files/neg/names-defaults-neg.scala') diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 119b415d51..ba4c962f34 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -554,15 +554,19 @@ trait NamesDefaults { self: Analyzer => arg match { case arg @ AssignOrNamedArg(Ident(name), rhs) => def matchesName(param: Symbol) = { - def checkDeprecation = when(param.deprecatedParamName) { case Some(`name`) => true } + def checkDeprecation(anonOK: Boolean) = + when (param.deprecatedParamName) { + case Some(`name`) => true + case Some(nme.NO_NAME) => anonOK + } def checkName = { val res = param.name == name - if (res && checkDeprecation) + if (res && checkDeprecation(true)) context0.deprecationWarning(arg.pos, param, s"naming parameter $name has been deprecated.") res } def checkAltName = { - val res = checkDeprecation + val res = checkDeprecation(false) if (res) context0.deprecationWarning(arg.pos, param, s"the parameter name $name has been deprecated. Use ${param.name} instead.") res diff --git a/src/library/scala/deprecatedName.scala b/src/library/scala/deprecatedName.scala index 07c5c8925c..a0d3aa829b 100644 --- a/src/library/scala/deprecatedName.scala +++ b/src/library/scala/deprecatedName.scala @@ -29,4 +29,6 @@ import scala.annotation.meta._ * @since 2.8.1 */ @param -class deprecatedName(name: Symbol) extends scala.annotation.StaticAnnotation +class deprecatedName(name: Symbol) extends scala.annotation.StaticAnnotation { + def this() = this(Symbol("")) +} diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index f2aa14b866..293af68c5f 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -858,7 +858,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => def isDeprecated = hasAnnotation(DeprecatedAttr) def deprecationMessage = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 0) def deprecationVersion = getAnnotation(DeprecatedAttr) flatMap (_ stringArg 1) - def deprecatedParamName = getAnnotation(DeprecatedNameAttr) flatMap (_ symbolArg 0) + def deprecatedParamName = getAnnotation(DeprecatedNameAttr) flatMap (_ symbolArg 0 orElse Some(nme.NO_NAME)) def hasDeprecatedInheritanceAnnotation = hasAnnotation(DeprecatedInheritanceAttr) def deprecatedInheritanceMessage diff --git a/test/files/neg/names-defaults-neg.check b/test/files/neg/names-defaults-neg.check index 249d227e93..d929cf23ec 100644 --- a/test/files/neg/names-defaults-neg.check +++ b/test/files/neg/names-defaults-neg.check @@ -121,68 +121,71 @@ names-defaults-neg.scala:93: error: parameter 'b' is already specified at parame names-defaults-neg.scala:96: warning: naming parameter deprNam4Arg has been deprecated. deprNam4(deprNam4Arg = null) ^ -names-defaults-neg.scala:100: error: unknown parameter name: m +names-defaults-neg.scala:98: warning: naming parameter deprNam5Arg has been deprecated. + deprNam5(deprNam5Arg = null) + ^ +names-defaults-neg.scala:102: error: unknown parameter name: m f3818(y = 1, m = 1) ^ -names-defaults-neg.scala:133: error: reference to var2 is ambiguous; it is both a method parameter and a variable in scope. +names-defaults-neg.scala:135: error: reference to var2 is ambiguous; it is both a method parameter and a variable in scope. delay(var2 = 40) ^ -names-defaults-neg.scala:136: error: missing parameter type for expanded function ((x$1) => a = x$1) +names-defaults-neg.scala:138: error: missing parameter type for expanded function ((x$1) => a = x$1) val taf2: Int => Unit = testAnnFun(a = _, b = get("+")) ^ -names-defaults-neg.scala:136: error: not found: value a +names-defaults-neg.scala:138: error: not found: value a val taf2: Int => Unit = testAnnFun(a = _, b = get("+")) ^ -names-defaults-neg.scala:136: error: not found: value get +names-defaults-neg.scala:138: error: not found: value get val taf2: Int => Unit = testAnnFun(a = _, b = get("+")) ^ -names-defaults-neg.scala:137: error: parameter 'a' is already specified at parameter position 1 +names-defaults-neg.scala:139: error: parameter 'a' is already specified at parameter position 1 val taf3 = testAnnFun(b = _: String, a = get(8)) ^ -names-defaults-neg.scala:138: error: missing parameter type for expanded function ((x$3) => testAnnFun(x$3, ((x$4) => b = x$4))) +names-defaults-neg.scala:140: error: missing parameter type for expanded function ((x$3) => testAnnFun(x$3, ((x$4) => b = x$4))) val taf4: (Int, String) => Unit = testAnnFun(_, b = _) ^ -names-defaults-neg.scala:138: error: missing parameter type for expanded function ((x$4) => b = x$4) +names-defaults-neg.scala:140: error: missing parameter type for expanded function ((x$4) => b = x$4) val taf4: (Int, String) => Unit = testAnnFun(_, b = _) ^ -names-defaults-neg.scala:138: error: not found: value b +names-defaults-neg.scala:140: error: not found: value b val taf4: (Int, String) => Unit = testAnnFun(_, b = _) ^ -names-defaults-neg.scala:146: error: variable definition needs type because 'x' is used as a named argument in its body. +names-defaults-neg.scala:148: error: variable definition needs type because 'x' is used as a named argument in its body. def t3 { var x = t.f(x = 1) } ^ -names-defaults-neg.scala:149: error: variable definition needs type because 'x' is used as a named argument in its body. +names-defaults-neg.scala:151: error: variable definition needs type because 'x' is used as a named argument in its body. object t6 { var x = t.f(x = 1) } ^ -names-defaults-neg.scala:149: warning: type-checking the invocation of method f checks if the named argument expression 'x = ...' is a valid assignment +names-defaults-neg.scala:151: warning: type-checking the invocation of method f checks if the named argument expression 'x = ...' is a valid assignment in the current scope. The resulting type inference error (see above) can be fixed by providing an explicit type in the local definition for x. object t6 { var x = t.f(x = 1) } ^ -names-defaults-neg.scala:152: error: variable definition needs type because 'x' is used as a named argument in its body. +names-defaults-neg.scala:154: error: variable definition needs type because 'x' is used as a named argument in its body. class t9 { var x = t.f(x = 1) } ^ -names-defaults-neg.scala:152: warning: type-checking the invocation of method f checks if the named argument expression 'x = ...' is a valid assignment +names-defaults-neg.scala:154: warning: type-checking the invocation of method f checks if the named argument expression 'x = ...' is a valid assignment in the current scope. The resulting type inference error (see above) can be fixed by providing an explicit type in the local definition for x. class t9 { var x = t.f(x = 1) } ^ -names-defaults-neg.scala:166: error: variable definition needs type because 'x' is used as a named argument in its body. +names-defaults-neg.scala:168: error: variable definition needs type because 'x' is used as a named argument in its body. def u3 { var x = u.f(x = 1) } ^ -names-defaults-neg.scala:169: error: variable definition needs type because 'x' is used as a named argument in its body. +names-defaults-neg.scala:171: error: variable definition needs type because 'x' is used as a named argument in its body. def u6 { var x = u.f(x = "32") } ^ -names-defaults-neg.scala:172: error: reference to x is ambiguous; it is both a method parameter and a variable in scope. +names-defaults-neg.scala:174: error: reference to x is ambiguous; it is both a method parameter and a variable in scope. def u9 { var x: Int = u.f(x = 1) } ^ -names-defaults-neg.scala:179: error: variable definition needs type because 'x' is used as a named argument in its body. +names-defaults-neg.scala:181: error: variable definition needs type because 'x' is used as a named argument in its body. class u15 { var x = u.f(x = 1) } ^ -names-defaults-neg.scala:179: warning: type-checking the invocation of method f checks if the named argument expression 'x = ...' is a valid assignment +names-defaults-neg.scala:181: warning: type-checking the invocation of method f checks if the named argument expression 'x = ...' is a valid assignment in the current scope. The resulting type inference error (see above) can be fixed by providing an explicit type in the local definition for x. class u15 { var x = u.f(x = 1) } ^ -names-defaults-neg.scala:182: error: reference to x is ambiguous; it is both a method parameter and a variable in scope. +names-defaults-neg.scala:184: error: reference to x is ambiguous; it is both a method parameter and a variable in scope. class u18 { var x: Int = u.f(x = 1) } ^ -5 warnings found +6 warnings found 46 errors found diff --git a/test/files/neg/names-defaults-neg.scala b/test/files/neg/names-defaults-neg.scala index d11c9910a1..c809b9a7a2 100644 --- a/test/files/neg/names-defaults-neg.scala +++ b/test/files/neg/names-defaults-neg.scala @@ -94,6 +94,8 @@ object Test extends App { def deprNam4(@deprecatedName('deprNam4Arg) deprNam4Arg: String) = 0 deprNam4(deprNam4Arg = null) + def deprNam5(@deprecatedName deprNam5Arg: String) = 0 + deprNam5(deprNam5Arg = null) // t3818 def f3818(x: Int = 1, y: Int, z: Int = 1) = 0 -- cgit v1.2.3