@@ -503,7 +503,21 @@ trait Applications extends Compatibility {
503503 def infoStr = if methType.isErroneous then " " else i " : $methType"
504504 i " ${err.refStr(methRef)}$infoStr"
505505
506- /** Re-order arguments to correctly align named arguments */
506+ /** Re-order arguments to correctly align named arguments
507+ * Issue errors in the following situations:
508+ *
509+ * - "positional after named argument" if a positional argument follows a named
510+ * argument and one of the following is true:
511+ *
512+ * - There is a formal argument before the argument position
513+ * that has not yet been instantiated with a previous actual argument,
514+ * (either named or positional), or
515+ * - The formal parameter at the argument position is also mentioned
516+ * in a subsequent named parameter.
517+ * - "parameter already instantiated" if a two named arguments have the same name.
518+ * - "does not have parameter" if a named parameter does not mention a formal
519+ * parameter name.
520+ */
507521 def reorder [T <: Untyped ](args : List [Trees .Tree [T ]]): List [Trees .Tree [T ]] = {
508522
509523 /** @param pnames The list of parameter names that are missing arguments
@@ -517,40 +531,43 @@ trait Applications extends Compatibility {
517531 * 2. For every `(name -> arg)` in `nameToArg`, `arg` is an element of `args`
518532 */
519533 def handleNamed (pnames : List [Name ], args : List [Trees .Tree [T ]],
520- nameToArg : Map [Name , Trees .NamedArg [T ]], toDrop : Set [Name ]): List [Trees .Tree [T ]] = pnames match {
534+ nameToArg : Map [Name , Trees .NamedArg [T ]], toDrop : Set [Name ],
535+ missingArgs : Boolean ): List [Trees .Tree [T ]] = pnames match {
521536 case pname :: pnames1 if nameToArg contains pname =>
522537 // there is a named argument for this parameter; pick it
523- nameToArg(pname) :: handleNamed(pnames1, args, nameToArg - pname, toDrop + pname)
538+ nameToArg(pname) :: handleNamed(pnames1, args, nameToArg - pname, toDrop + pname, missingArgs )
524539 case _ =>
525540 def pnamesRest = if (pnames.isEmpty) pnames else pnames.tail
526541 args match {
527542 case (arg @ NamedArg (aname, _)) :: args1 =>
528543 if (toDrop contains aname) // argument is already passed
529- handleNamed(pnames, args1, nameToArg, toDrop - aname)
544+ handleNamed(pnames, args1, nameToArg, toDrop - aname, missingArgs )
530545 else if ((nameToArg contains aname) && pnames.nonEmpty) // argument is missing, pass an empty tree
531- genericEmptyTree :: handleNamed(pnames.tail, args, nameToArg, toDrop)
546+ genericEmptyTree :: handleNamed(pnames.tail, args, nameToArg, toDrop, missingArgs = true )
532547 else { // name not (or no longer) available for named arg
533548 def msg =
534549 if (methodType.paramNames contains aname)
535550 em " parameter $aname of $methString is already instantiated "
536551 else
537552 em " $methString does not have a parameter $aname"
538553 fail(msg, arg.asInstanceOf [Arg ])
539- arg :: handleNamed(pnamesRest, args1, nameToArg, toDrop)
554+ arg :: handleNamed(pnamesRest, args1, nameToArg, toDrop, missingArgs )
540555 }
541556 case arg :: args1 =>
542- arg :: handleNamed(pnamesRest, args1, nameToArg, toDrop) // unnamed argument; pick it
557+ if toDrop.nonEmpty || missingArgs then
558+ report.error(i " positional after named argument " , arg.srcPos)
559+ arg :: handleNamed(pnamesRest, args1, nameToArg, toDrop, missingArgs) // unnamed argument; pick it
543560 case Nil => // no more args, continue to pick up any preceding named args
544561 if (pnames.isEmpty) Nil
545- else handleNamed(pnamesRest, args, nameToArg, toDrop)
562+ else handleNamed(pnamesRest, args, nameToArg, toDrop, missingArgs )
546563 }
547564 }
548565
549566 def handlePositional (pnames : List [Name ], args : List [Trees .Tree [T ]]): List [Trees .Tree [T ]] =
550567 args match {
551568 case (arg : NamedArg @ unchecked) :: _ =>
552569 val nameAssocs = for (case arg @ NamedArg (name, _) <- args) yield (name, arg)
553- handleNamed(pnames, args, nameAssocs.toMap, Set ())
570+ handleNamed(pnames, args, nameAssocs.toMap, toDrop = Set (), missingArgs = false )
554571 case arg :: args1 =>
555572 arg :: handlePositional(if (pnames.isEmpty) Nil else pnames.tail, args1)
556573 case Nil => Nil
0 commit comments