Skip to content

Commit da42220

Browse files
committed
Named arg may be deprecatedName
1 parent bb03c8c commit da42220

File tree

4 files changed

+76
-17
lines changed

4 files changed

+76
-17
lines changed

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,21 @@ trait Applications extends Compatibility {
635635

636636
inline def tailOf[A](list: List[A]): List[A] = if list.isEmpty then list else list.tail // list.drop(1)
637637

638+
def hasDeprecatedName(pname: Name, other: Name, t: Trees.Tree[T]): Boolean = !ctx.isAfterTyper &&
639+
methRef.symbol.paramSymss.flatten.find(_.name == pname).flatMap(_.getAnnotation(defn.DeprecatedNameAnnot)).match
640+
case Some(annot) =>
641+
val name = annot.argumentConstantString(0)
642+
val version = annot.argumentConstantString(1).filter(!_.isEmpty)
643+
val since = version.map(v => s" (since $v)").getOrElse("")
644+
name.map(_.toTermName) match
645+
case Some(`other`) =>
646+
report.deprecationWarning(em"the parameter name $other is deprecated$since: use $pname instead", t.srcPos)
647+
case Some(`pname`) | None =>
648+
report.deprecationWarning(em"naming parameter $pname is deprecated$since", t.srcPos)
649+
case _ =>
650+
true
651+
case _ => false
652+
638653
/** Reorder the suffix of named args per a list of required names.
639654
*
640655
* @param pnames The list of parameter names that are missing arguments
@@ -650,25 +665,32 @@ trait Applications extends Compatibility {
650665
*/
651666
def handleNamed(pnames: List[Name], args: List[Trees.Tree[T]],
652667
nameToArg: Map[Name, Trees.NamedArg[T]], toDrop: Set[Name],
653-
missingArgs: Boolean): List[Trees.Tree[T]] = pnames match
654-
case pname :: pnames if nameToArg.contains(pname) =>
655-
// there is a named argument for this parameter; pick it
656-
nameToArg(pname) :: handleNamed(pnames, args, nameToArg - pname, toDrop + pname, missingArgs)
668+
missingArgs: Boolean): List[Trees.Tree[T]] =
669+
pnames match
670+
case pname :: pnames if nameToArg.contains(pname) => // use the named argument for this parameter
671+
val arg = nameToArg(pname)
672+
hasDeprecatedName(pname, nme.NO_NAME, arg)
673+
arg :: handleNamed(pnames, args, nameToArg - pname, toDrop + pname, missingArgs)
657674
case _ =>
658675
args match
659-
case (arg @ NamedArg(aname, _)) :: args1 =>
660-
if toDrop.contains(aname) // named argument is already passed
661-
then handleNamed(pnames, args1, nameToArg, toDrop - aname, missingArgs)
662-
else if nameToArg.contains(aname) && pnames.nonEmpty // argument is missing, pass an empty tree
663-
then genericEmptyTree :: handleNamed(pnames.tail, args, nameToArg, toDrop, missingArgs = true)
676+
case allArgs @ (arg @ NamedArg(aname, _)) :: args =>
677+
if toDrop.contains(aname) then // named argument was already picked
678+
handleNamed(pnames, args, nameToArg, toDrop - aname, missingArgs)
679+
else if pnames.nonEmpty && nameToArg.contains(aname) then
680+
val pname = pnames.head
681+
if hasDeprecatedName(pname, aname, arg) then // name was deprecated alt, so try again with canonical name
682+
val parg = cpy.NamedArg(arg)(pname, arg.arg).asInstanceOf[Trees.NamedArg[T]]
683+
handleNamed(pnames, parg :: args, nameToArg.removed(aname).updated(pname, parg), toDrop, missingArgs)
684+
else // argument for pname is missing, pass an empty tree
685+
genericEmptyTree :: handleNamed(pnames.tail, allArgs, nameToArg, toDrop, missingArgs = true)
664686
else // name not (or no longer) available for named arg
665687
def msg =
666688
if methodType.paramNames.contains(aname) then
667689
em"parameter $aname of $methString is already instantiated"
668690
else
669691
em"$methString does not have a parameter $aname"
670692
fail(msg, arg.asInstanceOf[Arg])
671-
arg :: handleNamed(tailOf(pnames), args1, nameToArg, toDrop, missingArgs)
693+
arg :: handleNamed(tailOf(pnames), args, nameToArg, toDrop, missingArgs)
672694
case arg :: args =>
673695
if toDrop.nonEmpty || missingArgs then
674696
report.error(i"positional after named argument", arg.srcPos)
@@ -680,8 +702,10 @@ trait Applications extends Compatibility {
680702
/** Skip prefix of positional args, then handleNamed */
681703
def handlePositional(pnames: List[Name], args: List[Trees.Tree[T]]): List[Trees.Tree[T]] =
682704
args match
705+
case (arg @ NamedArg(name, _)) :: args if !pnames.isEmpty && pnames.head == name =>
706+
hasDeprecatedName(name, nme.NO_NAME, arg)
707+
arg :: handlePositional(pnames.tail, args)
683708
case (_: NamedArg) :: _ =>
684-
//val nameAssocs = for case arg @ NamedArg(name, _) <- args yield (name, arg)
685709
val nameAssocs = args.collect { case arg @ NamedArg(name, _) => name -> arg }
686710
handleNamed(pnames, args, nameAssocs.toMap, toDrop = Set.empty, missingArgs = false)
687711
case arg :: args =>

tests/neg/i18122.check

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,18 @@
3030
23 | bar1(ys = 1) // error: missing arg
3131
| ^^^^^^^^^^^^
3232
| missing argument for parameter x of method bar1 in object Test: (x: Int, ys: Int*): Unit
33-
-- Error: tests/neg/i18122.scala:43:16 ---------------------------------------------------------------------------------
33+
-- Error: tests/neg/i18122.scala:43:22 ---------------------------------------------------------------------------------
3434
43 | bar1(x = 1, 2, ys = 3) // error: positional after named
35-
| ^
36-
| positional after named argument
35+
| ^^^^^^
36+
| parameter ys of method bar1 in object Test: (x: Int, ys: Int*): Unit is already instantiated
3737
-- Error: tests/neg/i18122.scala:44:18 ---------------------------------------------------------------------------------
3838
44 | bar1(1, 2, ys = 3) // error: parameter ys is already instantiated
3939
| ^^^^^^
4040
| parameter ys of method bar1 in object Test: (x: Int, ys: Int*): Unit is already instantiated
41-
-- Error: tests/neg/i18122.scala:45:16 ---------------------------------------------------------------------------------
41+
-- Error: tests/neg/i18122.scala:45:22 ---------------------------------------------------------------------------------
4242
45 | bar2(x = 1, 2, ys = 3) // error: positional after named
43-
| ^
44-
| positional after named argument
43+
| ^^^^^^
44+
| parameter ys of method bar2 in object Test: (x: Int, ys: Int*): Unit is already instantiated
4545
-- Error: tests/neg/i18122.scala:46:17 ---------------------------------------------------------------------------------
4646
46 | bar1(ys = 1, 2, x = 3) // error: positional after named
4747
| ^

tests/warn/i19077.check

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
-- Deprecation Warning: tests/warn/i19077.scala:8:6 --------------------------------------------------------------------
2+
8 | f(x = 1, 2, 3) // warn
3+
| ^^^^^
4+
| naming parameter x is deprecated
5+
-- Deprecation Warning: tests/warn/i19077.scala:9:9 --------------------------------------------------------------------
6+
9 | f(1, y = 2, 3) // warn
7+
| ^^^^^
8+
| naming parameter y is deprecated
9+
-- Deprecation Warning: tests/warn/i19077.scala:10:12 ------------------------------------------------------------------
10+
10 | f(1, 2, w = 3) // warn
11+
| ^^^^^
12+
| the parameter name w is deprecated: use z instead
13+
-- Deprecation Warning: tests/warn/i19077.scala:11:13 ------------------------------------------------------------------
14+
11 | f(w = 3, x = 1, y = 2) // warn // warn // warn
15+
| ^^^^^
16+
| naming parameter x is deprecated
17+
-- Deprecation Warning: tests/warn/i19077.scala:11:20 ------------------------------------------------------------------
18+
11 | f(w = 3, x = 1, y = 2) // warn // warn // warn
19+
| ^^^^^
20+
| naming parameter y is deprecated
21+
-- Deprecation Warning: tests/warn/i19077.scala:11:6 -------------------------------------------------------------------
22+
11 | f(w = 3, x = 1, y = 2) // warn // warn // warn
23+
| ^^^^^
24+
| the parameter name w is deprecated: use z instead

tests/warn/i19077.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//> using options -deprecation
2+
3+
def f(@deprecatedName("x") x: Int, @deprecatedName y: Int, @deprecatedName("w") z: Int) = x+y+z
4+
5+
@main def Test =
6+
f(1, 2, 3) // nowarn
7+
f(1, 2, z = 3) // nowarn
8+
f(x = 1, 2, 3) // warn
9+
f(1, y = 2, 3) // warn
10+
f(1, 2, w = 3) // warn
11+
f(w = 3, x = 1, y = 2) // warn // warn // warn

0 commit comments

Comments
 (0)