Skip to content

Commit

Permalink
Merge pull request #2785 from dotty-staging/fix-#2778
Browse files Browse the repository at this point in the history
Fix #2778: Fix handling of named parameters
  • Loading branch information
odersky committed Jun 23, 2017
2 parents 73618f8 + 1058374 commit 76e7bb5
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 10 deletions.
29 changes: 19 additions & 10 deletions compiler/src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -260,37 +260,46 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
* 1. `(args diff toDrop)` can be reordered to match `pnames`
* 2. For every `(name -> arg)` in `nameToArg`, `arg` is an element of `args`
*/
def recur(pnames: List[Name], args: List[Trees.Tree[T]],
nameToArg: Map[Name, Trees.NamedArg[T]], toDrop: Set[Name]): List[Trees.Tree[T]] = pnames match {
def handleNamed(pnames: List[Name], args: List[Trees.Tree[T]],
nameToArg: Map[Name, Trees.NamedArg[T]], toDrop: Set[Name]): List[Trees.Tree[T]] = pnames match {
case pname :: pnames1 if nameToArg contains pname =>
// there is a named argument for this parameter; pick it
nameToArg(pname) :: recur(pnames1, args, nameToArg - pname, toDrop + pname)
nameToArg(pname) :: handleNamed(pnames1, args, nameToArg - pname, toDrop + pname)
case _ =>
def pnamesRest = if (pnames.isEmpty) pnames else pnames.tail
args match {
case (arg @ NamedArg(aname, _)) :: args1 =>
if (toDrop contains aname) // argument is already passed
recur(pnames, args1, nameToArg, toDrop - aname)
handleNamed(pnames, args1, nameToArg, toDrop - aname)
else if ((nameToArg contains aname) && pnames.nonEmpty) // argument is missing, pass an empty tree
genericEmptyTree :: recur(pnames.tail, args, nameToArg, toDrop)
genericEmptyTree :: handleNamed(pnames.tail, args, nameToArg, toDrop)
else { // name not (or no longer) available for named arg
def msg =
if (methodType.paramNames contains aname)
s"parameter $aname of $methString is already instantiated"
else
s"$methString does not have a parameter $aname"
fail(msg, arg.asInstanceOf[Arg])
arg :: recur(pnamesRest, args1, nameToArg, toDrop)
arg :: handleNamed(pnamesRest, args1, nameToArg, toDrop)
}
case arg :: args1 =>
arg :: recur(pnamesRest, args1, nameToArg, toDrop) // unnamed argument; pick it
arg :: handleNamed(pnamesRest, args1, nameToArg, toDrop) // unnamed argument; pick it
case Nil => // no more args, continue to pick up any preceding named args
if (pnames.isEmpty) Nil
else recur(pnamesRest, args, nameToArg, toDrop)
else handleNamed(pnamesRest, args, nameToArg, toDrop)
}
}
val nameAssocs = for (arg @ NamedArg(name, _) <- args) yield (name, arg)
recur(methodType.paramNames, args, nameAssocs.toMap, Set())

def handlePositional(pnames: List[Name], args: List[Trees.Tree[T]]): List[Trees.Tree[T]] =
args match {
case (arg: NamedArg) :: _ =>
val nameAssocs = for (arg @ NamedArg(name, _) <- args) yield (name, arg)
handleNamed(pnames, args, nameAssocs.toMap, Set())
case arg :: args1 => arg :: handlePositional(pnames.tail, args1)
case Nil => Nil
}

handlePositional(methodType.paramNames, args)
}

/** Splice new method reference into existing application */
Expand Down
9 changes: 9 additions & 0 deletions tests/neg/i2778.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
object Main {
def printName(first: String, last: String): Unit = {
println(first + " " + last)
}

def main(args: Array[String]): Unit = {
printName("John", first = "Smith") // error: parameter is already instantiated
}
}

0 comments on commit 76e7bb5

Please sign in to comment.