diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index f17889b9bbfd..1d1122e65f16 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -509,14 +509,22 @@ trait Applications extends Compatibility { if (success) formals match { case formal :: formals1 => + def checkNoVarArg(arg: Arg) = + if !ctx.isAfterTyper && isVarArg(arg) then + val addendum = + if formal.isRepeatedParam then + i"it is not the only argument to be passed to the corresponding repeated parameter $formal" + else + i"the corresponding parameter has type $formal which is not a repeated parameter type" + fail(em"Sequence argument type annotation `*` cannot be used here:\n$addendum", arg) + /** Add result of typing argument `arg` against parameter type `formal`. * @return The remaining formal parameter types. If the method is parameter-dependent * this means substituting the actual argument type for the current formal parameter * in the remaining formal parameters. */ - def addTyped(arg: Arg, formal: Type): List[Type] = - if !ctx.isAfterTyper && isVarArg(arg) && !formal.isRepeatedParam then - fail(i"Sequence argument type annotation `: _*` cannot be used here: the corresponding parameter has type $formal which is not a repeated parameter type", arg) + def addTyped(arg: Arg): List[Type] = + if !formal.isRepeatedParam then checkNoVarArg(arg) addArg(typedArg(arg, formal), formal) if methodType.isParamDependent && typeOfArg(arg).exists then // `typeOfArg(arg)` could be missing because the evaluation of `arg` produced type errors @@ -553,9 +561,9 @@ trait Applications extends Compatibility { def implicitArg = implicitArgTree(formal, appPos.span) if !defaultArg.isEmpty then - matchArgs(args1, addTyped(treeToArg(defaultArg), formal), n + 1) + matchArgs(args1, addTyped(treeToArg(defaultArg)), n + 1) else if methodType.isContextualMethod && ctx.mode.is(Mode.ImplicitsEnabled) then - matchArgs(args1, addTyped(treeToArg(implicitArg), formal), n + 1) + matchArgs(args1, addTyped(treeToArg(implicitArg)), n + 1) else missingArg(n) } @@ -563,13 +571,18 @@ trait Applications extends Compatibility { if (formal.isRepeatedParam) args match { case arg :: Nil if isVarArg(arg) => - addTyped(arg, formal) + addTyped(arg) case (arg @ Typed(Literal(Constant(null)), _)) :: Nil if ctx.isAfterTyper => - addTyped(arg, formal) + addTyped(arg) case _ => val elemFormal = formal.widenExpr.argTypesLo.head val typedArgs = - harmonic(harmonizeArgs, elemFormal)(args.map(typedArg(_, elemFormal))) + harmonic(harmonizeArgs, elemFormal) { + args.map { arg => + checkNoVarArg(arg) + typedArg(arg, elemFormal) + } + } typedArgs.foreach(addArg(_, elemFormal)) makeVarArg(args.length, elemFormal) } @@ -577,7 +590,7 @@ trait Applications extends Compatibility { case EmptyTree :: args1 => tryDefault(n, args1) case arg :: args1 => - matchArgs(args1, addTyped(arg, formal), n + 1) + matchArgs(args1, addTyped(arg), n + 1) case nil => tryDefault(n, args) } diff --git a/docs/docs/reference/changed-features/vararg-splices.md b/docs/docs/reference/changed-features/vararg-splices.md index 7667953112c0..085481a4c2c0 100644 --- a/docs/docs/reference/changed-features/vararg-splices.md +++ b/docs/docs/reference/changed-features/vararg-splices.md @@ -6,8 +6,8 @@ title: "Vararg Splices" The syntax of vararg splices in patterns and function arguments has changed. The new syntax uses a postfix `*`, analogously to how a vararg parameter is declared. ```scala -val arr = Array(1, 2, 3) -val lst = List(0, arr*) // vararg splice argument +val arr = Array(0, 1, 2, 3) +val lst = List(arr*) // vararg splice argument lst match case List(0, 1, xs*) => println(xs) // binds xs to Seq(2, 3) case List(1, _*) => // wildcard pattern @@ -16,7 +16,7 @@ lst match The old syntax for splice arguments will be phased out. ```scala -/*!*/ val lst = List(0, arr: _*) // syntax error +/*!*/ val lst = List(arr: _*) // syntax error lst match case List(1, 2, xs @ _*) // ok, equivalent to `xs*` ``` diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/MemberRenderer.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/MemberRenderer.scala index 3636f75b56a8..560f50b259b7 100644 --- a/scaladoc/src/dotty/tools/scaladoc/renderers/MemberRenderer.scala +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/MemberRenderer.scala @@ -83,10 +83,11 @@ class MemberRenderer(signatureRenderer: SignatureRenderer)(using DocContext) ext val message = named.find(_.name.get == "message") val since = named.find(_.name.get == "since") - val content = Seq( - since.map(s => code("[Since version ", parameter(s), "] ")), - message.map(m => parameter(m)), - m.docs.map(_.deprecated.toSeq.map(renderDocPart)):_* + val content = ( + Seq( + since.map(s => code("[Since version ", parameter(s), "] ")), + message.map(m => parameter(m))) + ++ m.docs.map(_.deprecated.toSeq.map(renderDocPart)) ).flatten Seq(dt("Deprecated"), dd(content:_*)) } diff --git a/tests/neg/i11419.scala b/tests/neg/i11419.scala new file mode 100644 index 000000000000..6ccc65855755 --- /dev/null +++ b/tests/neg/i11419.scala @@ -0,0 +1,7 @@ +object Test { + def main(args: Array[String]): Unit = { + val arr: Array[String] = Array("foo") + val lst = List("x", arr: _*) // error + println(lst) + } +} diff --git a/tests/pos/i5039.scala b/tests/pos/i5039.scala index d65c51863409..a14a6e812357 100644 --- a/tests/pos/i5039.scala +++ b/tests/pos/i5039.scala @@ -2,7 +2,4 @@ class I0 { List(null:_*) List[Null](null:_*) List[Nothing](null:_*) - List(1, 2, null:_*) - List(null, null:_*) - List(???, null:_*) } diff --git a/tests/pos/reference/vararg-patterns.scala b/tests/pos/reference/vararg-patterns.scala index aa49e0062553..3ddc860b7329 100644 --- a/tests/pos/reference/vararg-patterns.scala +++ b/tests/pos/reference/vararg-patterns.scala @@ -4,3 +4,9 @@ object t1 extends App { println(xs) val List(1, 2, _ *) = List(1, 2, 3) } +@main def Test = + val arr = Array(0, 1, 2, 3) + val lst = List(arr*) // vararg splice argument + lst match + case List(0, 1, xs*) => println(xs) // binds xs to Seq(2, 3) + case List(1, _*) => // wildcard pattern