Skip to content

Commit 7f48c4c

Browse files
authored
Merge pull request #11423 from dotty-staging/fix-11419
Tighten restriction for varargs splices
2 parents 2da2c0b + 0d1c021 commit 7f48c4c

File tree

6 files changed

+43
-19
lines changed

6 files changed

+43
-19
lines changed

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

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -509,14 +509,22 @@ trait Applications extends Compatibility {
509509
if (success) formals match {
510510
case formal :: formals1 =>
511511

512+
def checkNoVarArg(arg: Arg) =
513+
if !ctx.isAfterTyper && isVarArg(arg) then
514+
val addendum =
515+
if formal.isRepeatedParam then
516+
i"it is not the only argument to be passed to the corresponding repeated parameter $formal"
517+
else
518+
i"the corresponding parameter has type $formal which is not a repeated parameter type"
519+
fail(em"Sequence argument type annotation `*` cannot be used here:\n$addendum", arg)
520+
512521
/** Add result of typing argument `arg` against parameter type `formal`.
513522
* @return The remaining formal parameter types. If the method is parameter-dependent
514523
* this means substituting the actual argument type for the current formal parameter
515524
* in the remaining formal parameters.
516525
*/
517-
def addTyped(arg: Arg, formal: Type): List[Type] =
518-
if !ctx.isAfterTyper && isVarArg(arg) && !formal.isRepeatedParam then
519-
fail(i"Sequence argument type annotation `: _*` cannot be used here: the corresponding parameter has type $formal which is not a repeated parameter type", arg)
526+
def addTyped(arg: Arg): List[Type] =
527+
if !formal.isRepeatedParam then checkNoVarArg(arg)
520528
addArg(typedArg(arg, formal), formal)
521529
if methodType.isParamDependent && typeOfArg(arg).exists then
522530
// `typeOfArg(arg)` could be missing because the evaluation of `arg` produced type errors
@@ -553,31 +561,36 @@ trait Applications extends Compatibility {
553561
def implicitArg = implicitArgTree(formal, appPos.span)
554562

555563
if !defaultArg.isEmpty then
556-
matchArgs(args1, addTyped(treeToArg(defaultArg), formal), n + 1)
564+
matchArgs(args1, addTyped(treeToArg(defaultArg)), n + 1)
557565
else if methodType.isContextualMethod && ctx.mode.is(Mode.ImplicitsEnabled) then
558-
matchArgs(args1, addTyped(treeToArg(implicitArg), formal), n + 1)
566+
matchArgs(args1, addTyped(treeToArg(implicitArg)), n + 1)
559567
else
560568
missingArg(n)
561569
}
562570

563571
if (formal.isRepeatedParam)
564572
args match {
565573
case arg :: Nil if isVarArg(arg) =>
566-
addTyped(arg, formal)
574+
addTyped(arg)
567575
case (arg @ Typed(Literal(Constant(null)), _)) :: Nil if ctx.isAfterTyper =>
568-
addTyped(arg, formal)
576+
addTyped(arg)
569577
case _ =>
570578
val elemFormal = formal.widenExpr.argTypesLo.head
571579
val typedArgs =
572-
harmonic(harmonizeArgs, elemFormal)(args.map(typedArg(_, elemFormal)))
580+
harmonic(harmonizeArgs, elemFormal) {
581+
args.map { arg =>
582+
checkNoVarArg(arg)
583+
typedArg(arg, elemFormal)
584+
}
585+
}
573586
typedArgs.foreach(addArg(_, elemFormal))
574587
makeVarArg(args.length, elemFormal)
575588
}
576589
else args match {
577590
case EmptyTree :: args1 =>
578591
tryDefault(n, args1)
579592
case arg :: args1 =>
580-
matchArgs(args1, addTyped(arg, formal), n + 1)
593+
matchArgs(args1, addTyped(arg), n + 1)
581594
case nil =>
582595
tryDefault(n, args)
583596
}

docs/docs/reference/changed-features/vararg-splices.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ title: "Vararg Splices"
66
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.
77

88
```scala
9-
val arr = Array(1, 2, 3)
10-
val lst = List(0, arr*) // vararg splice argument
9+
val arr = Array(0, 1, 2, 3)
10+
val lst = List(arr*) // vararg splice argument
1111
lst match
1212
case List(0, 1, xs*) => println(xs) // binds xs to Seq(2, 3)
1313
case List(1, _*) => // wildcard pattern
@@ -16,7 +16,7 @@ lst match
1616
The old syntax for splice arguments will be phased out.
1717

1818
```scala
19-
/*!*/ val lst = List(0, arr: _*) // syntax error
19+
/*!*/ val lst = List(arr: _*) // syntax error
2020
lst match
2121
case List(1, 2, xs @ _*) // ok, equivalent to `xs*`
2222
```

scaladoc/src/dotty/tools/scaladoc/renderers/MemberRenderer.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,11 @@ class MemberRenderer(signatureRenderer: SignatureRenderer)(using DocContext) ext
8383
val message = named.find(_.name.get == "message")
8484
val since = named.find(_.name.get == "since")
8585

86-
val content = Seq(
87-
since.map(s => code("[Since version ", parameter(s), "] ")),
88-
message.map(m => parameter(m)),
89-
m.docs.map(_.deprecated.toSeq.map(renderDocPart)):_*
86+
val content = (
87+
Seq(
88+
since.map(s => code("[Since version ", parameter(s), "] ")),
89+
message.map(m => parameter(m)))
90+
++ m.docs.map(_.deprecated.toSeq.map(renderDocPart))
9091
).flatten
9192
Seq(dt("Deprecated"), dd(content:_*))
9293
}

tests/neg/i11419.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
object Test {
2+
def main(args: Array[String]): Unit = {
3+
val arr: Array[String] = Array("foo")
4+
val lst = List("x", arr: _*) // error
5+
println(lst)
6+
}
7+
}

tests/pos/i5039.scala

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,4 @@ class I0 {
22
List(null:_*)
33
List[Null](null:_*)
44
List[Nothing](null:_*)
5-
List(1, 2, null:_*)
6-
List(null, null:_*)
7-
List(???, null:_*)
85
}

tests/pos/reference/vararg-patterns.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,9 @@ object t1 extends App {
44
println(xs)
55
val List(1, 2, _ *) = List(1, 2, 3)
66
}
7+
@main def Test =
8+
val arr = Array(0, 1, 2, 3)
9+
val lst = List(arr*) // vararg splice argument
10+
lst match
11+
case List(0, 1, xs*) => println(xs) // binds xs to Seq(2, 3)
12+
case List(1, _*) => // wildcard pattern

0 commit comments

Comments
 (0)