Repository: scalameta/scalameta (scala)

Issue:
`invariant failed` error

## Required: Configuration ##

`.scalafmt.conf`

```
version = "3.10.1"
runner.dialect = scala213
```


## Required: Command-line parameters ##

```
$ scala --version           
Scala code runner version: 1.9.0
Scala version (default): 3.7.3
```



## Steps

```scala
trait A {
  def b(
     x: Int => List[
       Int
     ]*
  ): Int = 2
}
```

`scala fmt A.scala`


## Problem

```
org.scalafmt.cli.FailedToFormat: /Users/kenji/scalafmt-invariant-failed-err/A.scala

Caused by: org.scalameta.invariants.InvariantFailedException: invariant failed:
when verifying parentCheckOk.&&(org.scalameta.`package`.debug(this, parentPrefix, destination))
found that parentCheckOk is false
where TypeRepeatedImpl = List[
       Int
     ]*
where destination = res
where parentCheckOk = false
where parentPrefix = Type.Function
where this = List[
       Int
     ]*

	at scala.scalanative.runtime.StackTrace$.materializeStackTrace(Unknown Source)
	at scala.scalanative.runtime.StackTrace$.materializeStackTrace(Unknown Source)
	at scala.scalanative.runtime.StackTrace$.materializeStackTrace(Unknown Source)
	at scala.scalanative.runtime.StackTrace$.materializeStackTrace(Unknown Source)
	at scala.scalanative.runtime.StackTrace$.materializeStackTrace(Unknown Source)
	at scala.scalanative.runtime.StackTrace$.materializeStackTrace(Unknown Source)
	at scala.scalanative.runtime.StackTrace$.materializeStackTrace(Unknown Source)
	at scala.scalanative.runtime.StackTrace$.materializeStackTrace(Unknown Source)
	at scala.scalanative.runtime.StackTrace$.materializeStackTrace(Unknown Source)
	at scala.scalanative.runtime.StackTrace$.materializeStackTrace(Unknown Source)
	at scala.scalanative.runtime.StackTrace$.materializeStackTrace(Unknown Source)
	at scala.scalanative.runtime.StackTrace$.materializeStackTrace(Unknown Source)
	at scala.scalanative.runtime.StackTrace$.materializeStackTrace(Unknown Source)
	at scala.scalanative.runtime.StackTrace$.materializeStackTrace(Unknown Source)
```

## Expectation


## Workaround

use scalafmt 3.10.0

## Notes

Pull request:
Fixes #4344.

Patch:
diff --git a/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScalametaParser.scala b/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScalametaParser.scala
index e110117e5b..edaddb14bb 100644
--- a/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScalametaParser.scala
+++ b/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScalametaParser.scala
@@ -690,9 +690,16 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
     makeTupleType(lpPos, body, invalidLiteralUnitType)
   }
 
-  private def inParensOrTupleOrUnitExpr(): Term = {
+  private def inParensOrTupleOrUnitExpr(allowRepeated: Boolean): Term = {
     val lpPos = currIndex
-    val maybeTupleArgs = inParensOnOpenOr(commaSeparated(expr(location = PostfixStat)))(Nil)
+    val maybeTupleArgs = inParensOnOpenOr(
+      commaSeparated(expr(location = PostfixStat, allowRepeated = allowRepeated))
+    )(Nil)
+    if (maybeTupleArgs.lengthCompare(1) > 0) maybeTupleArgs.foreach {
+      case arg: Term.Repeated =>
+        syntaxError("repeated argument not allowed here", at = arg.tokens.last)
+      case _ =>
+    }
     makeTupleTerm(x => getTupleSingleTerm(maybeAnonymousFunction(x)))(lpPos, maybeTupleArgs)
   }
 
@@ -799,10 +806,10 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
       }).getOrElse(t)
     }
 
-    private def paramValueType(): Type = {
+    private def paramValueType(allowRepeated: Boolean = false): Type = {
       val startPos = currIndex
       def withRepeated(t: Type) =
-        if (isStar) { next(); autoEndPos(startPos)(Type.Repeated(t)) } else t
+        if (allowRepeated && isStar) { next(); autoEndPos(startPos)(Type.Repeated(t)) } else t
       def atInto() = {
         val intoPos = currIndex
         val mod = atPos(intoPos)(Mod.Into())
@@ -818,14 +825,15 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
     }
 
     def paramType(): Type = {
-      def byNameParamValueType = paramValueType()
+      def byNameParamValueType =
+        paramValueType(allowRepeated = dialect.allowByNameRepeatedParameters)
       currToken match {
         case _: RightArrow => autoPos { next(); Type.ByName(byNameParamValueType) }
         case soft.KwPureFunctionArrow() =>
           val startPos = currIndex
           next()
           withTypeCaptures(startPos)(autoEndPos(startPos)(Type.PureByName(byNameParamValueType)))
-        case _ => paramValueType()
+        case _ => paramValueType(allowRepeated = true)
       }
     }
 
@@ -1416,15 +1424,15 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
 
   def condExpr(): Term = inParens(expr())
 
-  def expr(): Term = expr(location = NoStat)
+  def expr(): Term = expr(location = NoStat, allowRepeated = false)
 
-  def quasiquoteExpr(): Term = expr(location = NoStat)
+  def quasiquoteExpr(): Term = expr(location = NoStat, allowRepeated = true)
 
-  def entrypointExpr(): Term = expr(location = NoStat)
+  def entrypointExpr(): Term = expr(location = NoStat, allowRepeated = false)
 
   def unquoteExpr(): Term = currToken match {
     case t: Ident => termName(t)
-    case _: LeftBrace => expr(location = UnquoteStat)
+    case _: LeftBrace => expr(location = UnquoteStat, allowRepeated = true)
     case _: KwThis => anonThis()
     case _ => syntaxError(
         "error in interpolated string: identifier, `this' or block expected",
@@ -1436,10 +1444,11 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
    * Deals with Scala 3 concept of {{{inline x match { ...}}}. Since matches can also be chained in
    * Scala 3 we need to create the Match first and only then add the the inline modifier.
    */
-  def inlineMatchClause(inlineMods: List[Mod]) = autoEndPos(inlineMods)(postfixExpr()) match {
-    case t: Term.Match => copyPos(t)(t.fullCopy(mods = inlineMods))
-    case other => syntaxError("`inline` must be followed by an `if` or a `match`", at = other.pos)
-  }
+  def inlineMatchClause(inlineMods: List[Mod]) =
+    autoEndPos(inlineMods)(postfixExpr(allowRepeated = false)) match {
+      case t: Term.Match => copyPos(t)(t.fullCopy(mods = inlineMods))
+      case other => syntaxError("`inline` must be followed by an `if` or a `match`", at = other.pos)
+    }
 
   private def matchClause(t: Term, startPos: Int, isSelect: Boolean = false) = {
     val cases =
@@ -1471,7 +1480,7 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
         else {
           // let's consider case when something can continue cond or start body
           val argsOrInitBody = currToken match {
-            case _: LeftParen => Some(inParensOrTupleOrUnitExpr())
+            case _: LeftParen => Some(inParensOrTupleOrUnitExpr(allowRepeated = false))
             case _: LeftBrace => Some(blockExprOnBrace())
             case _ => None
           }
@@ -1481,8 +1490,8 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
               autoEndPos(startPos)(Term.Apply(simpleExpr, args))
             }
             val simpleRest = simpleExprRest(simpleExprWithArgs, canApply = true, startPos = startPos)
-            Try(postfixExpr(startPos, simpleRest)).toOption.flatMap { x =>
-              val exprCond = exprOtherRest(startPos, x, location = NoStat)
+            Try(postfixExpr(startPos, simpleRest, allowRepeated = false)).toOption.flatMap { x =>
+              val exprCond = exprOtherRest(startPos, x, location = NoStat, allowRepeated = false)
               if (acceptIfAfterOptNL[T]) Some(exprCond -> None) else None
             }
           }
@@ -1491,8 +1500,8 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
             simpleExpr -> argsOrInitBody.map { t =>
               val startPos = t.begIndex
               val rest = simpleExprRest(t, canApply = true, startPos = startPos)
-              val init = postfixExpr(startPos, rest)
-              exprOtherRest(startPos, init, NoStat)
+              val init = postfixExpr(startPos, rest, allowRepeated = false)
+              exprOtherRest(startPos, init, NoStat, allowRepeated = false)
             }
           }
         }
@@ -1506,7 +1515,7 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
   // if yes, then nothing has to change here
   // if no, we need eschew autoPos here, because it forces those parentheses on the result of calling prefixExpr
   // see https://github.com/scalameta/scalameta/issues/1083 and https://github.com/scalameta/scalameta/issues/1223
-  def expr(location: Location): Term = {
+  def expr(location: Location, allowRepeated: Boolean): Term = {
     def inlineMod() = autoPos {
       accept[Ident]
       Mod.Inline()
@@ -1592,26 +1601,33 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
         case _: LeftBracket if dialect.allowPolymorphicFunctions =>
           val quants = typeParamClauseOpt()
           accept[RightArrow]
-          Term.PolyFunction(quants, expr(location))
+          Term.PolyFunction(quants, expr(location, allowRepeated))
         case _ =>
           val startPos = currIndex
-          val t: Term = postfixExpr()
-          exprOtherRest(startPos, t, location)
+          val t: Term = postfixExpr(allowRepeated)
+          exprOtherRest(startPos, t, location, allowRepeated)
       }
     }
     if (location.anonFuncOK) maybeAnonymousFunction(res) else res
   }
 
-  private def exprOtherRest(startPos: Int, prefix: Term, location: Location): Term = {
+  private def exprOtherRest(
+      startPos: Int,
+      prefix: Term,
+      location: Location,
+      allowRepeated: Boolean
+  ): Term = {
     @inline
     def addPos[T <: Tree](body: T) = autoEndPos(startPos)(body)
-    def repeatedTerm(t: Term, nextTokens: () => Unit): Term = addPos { nextTokens(); Term.Repeated(t) }
+    def repeatedTerm(t: Term, nextTokens: () => Unit): Term =
+      if (allowRepeated) addPos { nextTokens(); Term.Repeated(t) }
+      else syntaxError("repeated argument not allowed here", at = currToken)
     @tailrec
     def iter(t: Term): Term = currToken match {
       case _: Equals => t match {
           case _: Term.Ref | _: Term.Apply | _: Quasi =>
             next()
-            addPos(Term.Assign(t, expr(location = NoStat)))
+            addPos(Term.Assign(t, expr(location = NoStat, allowRepeated = true)))
           case _ => t
         }
       case _: Colon => getFewerBracesApplyOnColon(t, startPos) match {
@@ -1626,7 +1642,7 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
               // check out the `if (token.is[RightArrow]) { ... }` block below
               iter(addPos(Term.Ascribe(t, typeOrInfixType(location))))
         }
-      case soft.StarSplice() if peek[RightParen] => repeatedTerm(t, next)
+      case soft.StarSplice() if allowRepeated && peek[RightParen] => repeatedTerm(t, next)
       case _: KwMatch =>
         next()
         matchClause(t, startPos)
@@ -1942,17 +1958,17 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
       case _ => None
     }
 
-  def postfixExpr(): Term = {
+  def postfixExpr(allowRepeated: Boolean): Term = {
     val startPos = currIndex
 
     // Start the infix chain.
     // We'll use `a + b` as our running example.
-    val rhs0 = prefixExpr()
+    val rhs0 = prefixExpr(allowRepeated)
 
-    postfixExpr(startPos, rhs0)
+    postfixExpr(startPos, rhs0, allowRepeated)
   }
 
-  private def postfixExpr(startPos: Int, rhs0: Term): Term = {
+  private def postfixExpr(startPos: Int, rhs0: Term, allowRepeated: Boolean): Term = {
     val ctx = termInfixContext
     val base = ctx.stack
 
@@ -2023,7 +2039,7 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
         case t: Unquote =>
           val op = unquote[Term.Name](t)
           Some(getPostfixOrNextRhs(op))
-        case t: Ident if !(soft.StarSplice(t) && peek[RightParen]) =>
+        case t: Ident if !(allowRepeated && soft.StarSplice(t) && peek[RightParen]) =>
           val op = atCurPosNext(Term.Name(t.value))
           Some(getPostfixOrNextRhs(op))
         case _: KwMatch if dialect.allowMatchAsOperator =>
@@ -2062,7 +2078,7 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
     }
   }
 
-  def prefixExpr(): Term = currToken match {
+  def prefixExpr(allowRepeated: Boolean): Term = currToken match {
     case Unary((ident, unary)) =>
       val startPos = currIndex
       next()
@@ -2070,7 +2086,7 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
       def addPos(tree: Term) = autoEndPos(startPos)(tree)
       def rest(tree: Term) = simpleExprRest(tree, canApply = true, startPos = startPos)
       def applyUnary(term: Term) = addPos(Term.ApplyUnary(op, term))
-      def otherwise = simpleExpr0() match {
+      def otherwise = simpleExpr0(allowRepeated = true) match {
         case Success(result) => applyUnary(result)
         case Failure(_) =>
           // maybe it is not unary operator but simply an ident `trait - {...}`
@@ -2084,12 +2100,12 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
           next(); rest(addPos(Lit.Boolean(unary(tok.value))))
         case _ => otherwise
       }
-    case _ => simpleExpr()
+    case _ => simpleExpr(allowRepeated)
   }
 
-  def simpleExpr(): Term = simpleExpr0().get
+  def simpleExpr(allowRepeated: Boolean): Term = simpleExpr0(allowRepeated).get
 
-  private def simpleExpr0(): Try[Term] = {
+  private def simpleExpr0(allowRepeated: Boolean): Try[Term] = {
     var canApply = true
     val startPos = currIndex
     (currToken match {
@@ -2102,7 +2118,7 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
       case _: Xml.Start => Success(xmlTerm())
       case _: Ident | _: KwThis | _: KwSuper | _: Unquote => Success(path().become[Term])
       case _: Underscore => Success(atCurPosNext(Term.Placeholder()))
-      case _: LeftParen => Success(inParensOrTupleOrUnitExpr())
+      case _: LeftParen => Success(inParensOrTupleOrUnitExpr(allowRepeated = allowRepeated))
       case _: LeftBrace => canApply = false; Success(blockExprOnBrace())
       case _: Indentation.Indent => canApply = false; Success(blockExprOnIndent())
       case _: KwNew =>
@@ -2296,13 +2312,20 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
 
   private def argumentExprsOrPrefixExpr(location: Location): Term = {
     val isBrace = at[LeftBrace]
-    if (!isBrace && !at[LeftParen]) prefixExpr()
+    if (!isBrace && !at[LeftParen]) prefixExpr(allowRepeated = false)
     else {
+      def findRep(args: List[Term]): Option[Term.Repeated] = args.collectFirst {
+        case Term.Assign(_, rep: Term.Repeated) => rep
+        case rep: Term.Repeated => rep
+      }
       val lpPos = currIndex
       val args =
-        if (isBrace) checkNoTripleDot(blockExprOnBrace()) :: Nil
+        if (isBrace) checkNoTripleDot(blockExprOnBrace(allowRepeated = true)) :: Nil
         else inParensOnOpenOr(argumentExprsInParens(location))(Nil)
-      def getRest() = simpleExprRest(makeTupleTerm(lpPos, args), canApply = true, startPos = lpPos)
+      def getRest() = {
+        findRep(args).foreach(x => syntaxError("repeated argument not allowed here", at = x))
+        simpleExprRest(makeTupleTerm(lpPos, args), canApply = true, startPos = lpPos)
+      }
       currToken match {
         case _: Dot | _: OpenDelim | _: Underscore => getRest()
         // see ArgumentExprs in:
@@ -2319,11 +2342,11 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
 
   private def argumentExpr(location: Location): Term = currToken match {
     case t @ Ellipsis(2) => syntaxError(Messages.QuasiquoteRankMismatch(2, 1), at = t)
-    case _ => expr(location = location)
+    case _ => expr(location = location, allowRepeated = true)
   }
 
   private def getArgClauseOnBrace(): Term.ArgClause = autoPos {
-    val arg = blockExprOnBrace()
+    val arg = blockExprOnBrace(allowRepeated = true)
     Term.ArgClause(arg :: Nil)
   }
 
@@ -2337,8 +2360,18 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
     })(Term.ArgClause(Nil))
   )
 
-  private def argumentExprsInParens(location: Location = NoStat): List[Term] =
-    commaSeparated(argumentExpr(location))
+  private def argumentExprsInParens(location: Location = NoStat): List[Term] = {
+    @tailrec
+    def checkRep(exprsLeft: List[Term]): Unit = exprsLeft match {
+      case head :: tail =>
+        if (!head.is[Term.Repeated]) checkRep(tail)
+        else if (tail.nonEmpty) syntaxError("repeated argument not allowed here", at = head)
+      case _ =>
+    }
+    val exprs = commaSeparated(argumentExpr(location))
+    checkRep(exprs)
+    exprs
+  }
 
   private def checkNoTripleDot[T <: Tree](tree: T): T = tree match {
     case q: Quasi if q.rank == 2 => syntaxError(Messages.QuasiquoteRankMismatch(q.rank, 1), at = q)
@@ -2363,7 +2396,8 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
     else orElse
   }
 
-  private def blockRaw(): Term.Block = toBlockRaw(blockStatSeq())
+  private def blockRaw(allowRepeated: Boolean = false): Term.Block =
+    toBlockRaw(blockStatSeq(allowRepeated = allowRepeated))
 
   private def blockOnIndent(keepBlock: Boolean = false): Term = autoPosOpt(
     indentedOnOpen(blockStatSeq() match {
@@ -2376,13 +2410,16 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
     blockExprPartial[Indentation.Outdent](blockOnIndent(keepBlock))
 
   private def blockOnBrace(fstats: => List[Stat]): Term = autoPos(toBlockRaw(inBracesOnOpen(fstats)))
-  private def blockOnBrace(): Term = blockOnBrace(blockStatSeq())
-  private def blockExprOnBrace(isOptional: Boolean = false): Term =
-    blockExprPartial[RightBrace](if (isOptional) blockOnOther() else blockOnBrace())
+  private def blockOnBrace(allowRepeated: Boolean = false): Term =
+    blockOnBrace(blockStatSeq(allowRepeated = allowRepeated))
+  private def blockExprOnBrace(allowRepeated: Boolean = false, isOptional: Boolean = false): Term =
+    blockExprPartial[RightBrace](
+      if (isOptional) blockOnOther(allowRepeated) else blockOnBrace(allowRepeated)
+    )
 
-  private def blockOnOther(): Term = {
+  private def blockOnOther(allowRepeated: Boolean = false): Term = {
     val start = currIndex
-    blockStatSeq() match {
+    blockStatSeq(allowRepeated = allowRepeated) match {
       case (term: Term) :: Nil => term
       case (q: Quasi) :: Nil => q.become[Term]
       case stats => autoEndPos(start)(toBlockRaw(stats))
@@ -2395,7 +2432,7 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
       def caseBody() = {
         accept[RightArrow]
         if (at[Indentation.Indent]) blockExprOnIndent()
-        else if (forceSingleExpr) expr(location = BlockStat)
+        else if (forceSingleExpr) expr(location = BlockStat, allowRepeated = false)
         else blockOnOther()
       }
       @inline
@@ -2438,7 +2475,7 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
 
   private def guardOnIf(): Term = {
     next()
-    autoPos(postfixExpr())
+    autoPos(postfixExpr(allowRepeated = false))
   }
 
   private def enumeratorGuardOnIf() = autoPos(Enumerator.Guard(guardOnIf()))
@@ -4026,7 +4063,7 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
       packageOrPackageObjectDef(if (dialect.allowToplevelTerms) consumeStat else topStat)
     case _ if isDefIntro(currIndex) => TemplateOwnerContext.within(OwnedByClass)(nonLocalDefOrDcl())
     case _ if isAtEndMarker() => endMarker()
-    case _ if isIdentOrExprIntro(currToken) => stat(expr(location = NoStat))
+    case _ if isIdentOrExprIntro(currToken) => stat(expr(location = NoStat, allowRepeated = true))
     case t: Ellipsis => ellipsis[Stat](t, 1)
   }
 
@@ -4108,7 +4145,7 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
     case t: Unquote => unquote[Stat](t)
     case t: Ellipsis => ellipsis[Stat](t, 1)
     case _ if isAtEndMarker() => endMarker()
-    case _ if isIdentOrExprIntro(currToken) => expr(location = TemplateStat)
+    case _ if isIdentOrExprIntro(currToken) => expr(location = TemplateStat, allowRepeated = false)
   }
 
   private def refineStatSeq(): List[Stat] = listBy[Stat] { stats =>
@@ -4145,7 +4182,7 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
     }
   }
 
-  def blockStatSeq(): List[Stat] = listBy[Stat] { stats =>
+  def blockStatSeq(allowRepeated: Boolean = false): List[Stat] = listBy[Stat] { stats =>
     def notCaseDefEnd(): Boolean = currToken match {
       case _: RightParen | StatSeqEnd() => false
       case _: KwCase => !isCaseIntroOnKwCase()
@@ -4166,12 +4203,17 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) {
         else localDef(Some(atPos(implicitPos)(Mod.Implicit())))
       case t if !isNonlocalModifier(t) && isDefIntro(currIndex) => localDef(None)
       case _ if isAtEndMarker() => endMarker()
-      case _ if isIdentOrExprIntro(currToken) => stat(expr(location = BlockStat))
+      case _ if isIdentOrExprIntro(currToken) =>
+        stat(expr(location = BlockStat, allowRepeated = allowRepeated))
       case t: Ellipsis => ellipsis[Stat](t, 1)
       case _ => syntaxError("illegal start of statement", at = currToken)
     }
 
     if (cond()) doWhile(stats += getStat())(notCaseDefEnd() && { acceptStatSep(); cond() })
+    if (allowRepeated && stats.length > 1) stats.foreach {
+      case t: Term.Repeated => syntaxError("repeated argument not allowed here", at = t)
+      case _ =>
+    }
   }
 
   private def toPkgBody(startPos: Int)(stats: List[Stat]): Pkg.Body =


Test patch:
diff --git a/tests/shared/src/test/scala-2/scala/meta/tests/prettyprinters/SyntacticSuite.scala b/tests/shared/src/test/scala-2/scala/meta/tests/prettyprinters/SyntacticSuite.scala
index 09a25f1cdb..72843b8bec 100644
--- a/tests/shared/src/test/scala-2/scala/meta/tests/prettyprinters/SyntacticSuite.scala
+++ b/tests/shared/src/test/scala-2/scala/meta/tests/prettyprinters/SyntacticSuite.scala
@@ -928,18 +928,13 @@ class SyntacticSuite extends scala.meta.tests.parsers.ParseSuite {
     tapply(tapply(tname("foo"), tname("bar")), blk(Term.Repeated(tname("baz"))))
   ))
 
-  test("#1063 bad")(
-    runTestAssert[Stat](
-      "foo(bar) { val baz = qux; baz: _* }",
-      """|foo(bar) {
-         |  val baz = qux
-         |  baz: _*
-         |}""".stripMargin
-    )(tapply(
-      tapply("foo", "bar"),
-      blk(Defn.Val(Nil, List(patvar("baz")), None, "qux"), Term.Repeated("baz"))
-    ))
-  )
+  test("#1063 bad") {
+    val thrown = intercept[ParseException](term("foo(bar) { val baz = qux; baz: _* }"))
+    assertEquals(
+      thrown.getMessage.substring(0, 52),
+      "<input>:1: error: repeated argument not allowed here"
+    )
+  }
 
   test("#1384 char no unescaped LF") {
     val expr = "('\n')"
diff --git a/tests/shared/src/test/scala/scala/meta/tests/parsers/TermSuite.scala b/tests/shared/src/test/scala/scala/meta/tests/parsers/TermSuite.scala
index f3ad69560c..0023685fe0 100644
--- a/tests/shared/src/test/scala/scala/meta/tests/parsers/TermSuite.scala
+++ b/tests/shared/src/test/scala/scala/meta/tests/parsers/TermSuite.scala
@@ -442,7 +442,7 @@ class TermSuite extends ParseSuite {
 
   test("a + (bs: _*) * c")(intercept[ParseException](term("a + (bs: _*) * c")))
 
-  test("a + b: _*")(assertTerm("a + b: _*")(Term.Repeated(tinfix("a", "+", "b"))))
+  test("a + b: _*")(intercept[ParseException](term("a + b: _*")))
 
   test("foo(a + b: _*)")(assertTerm("foo(a + b: _*)")(
     tapply(tname("foo"), Term.Repeated(tinfix(tname("a"), "+", tname("b"))))
@@ -723,9 +723,12 @@ class TermSuite extends ParseSuite {
     tname("j")
   )))
 
-  test("#2720 infix with repeated arg not last")(
-    checkTerm("a op (b: _*, c)")(tinfix("a", "op", Term.Repeated("b"), "c"))
-  )
+  test("#2720 infix with repeated arg not last")(assertNoDiff(
+    intercept[ParseException](term("a op (b: _*, c)")).getMessage,
+    """|<input>:1: error: repeated argument not allowed here
+       |a op (b: _*, c)
+       |      ^""".stripMargin
+  ))
 
   test("#1384 string") {
     val tq = "\"" * 3
diff --git a/tests/shared/src/test/scala/scala/meta/tests/parsers/VarargParameterSuite.scala b/tests/shared/src/test/scala/scala/meta/tests/parsers/VarargParameterSuite.scala
index 037643f009..dc7c52966a 100644
--- a/tests/shared/src/test/scala/scala/meta/tests/parsers/VarargParameterSuite.scala
+++ b/tests/shared/src/test/scala/scala/meta/tests/parsers/VarargParameterSuite.scala
@@ -70,21 +70,8 @@ class VarargParameterSuite extends ParseSuite {
   )
 
   test("error on repeated byname parameter") {
-    check("def fx(x: => Int*): Int = 3")(Defn.Def(
-      Nil,
-      tname("fx"),
-      Nil,
-      List(List(tparam("x", Type.ByName(Type.Repeated("Int"))))),
-      Some("Int"),
-      lit(3)
-    ))
-    check("class Foo(bars: => Int*)")(Defn.Class(
-      Nil,
-      pname("Foo"),
-      Nil,
-      ctorp(tparam("bars", Type.ByName(Type.Repeated("Int")))),
-      tplNoBody()
-    ))
+    checkError("def fx(x: => Int*): Int = 3", "`)` expected but `identifier` found")
+    checkError("class Foo(bars: => Int*)", "`)` expected but `identifier` found")
   }
 
   test("error on multiple vararg parameters")(
@@ -106,4 +93,17 @@ class VarargParameterSuite extends ParseSuite {
     assert(obtained.contains(expected), s"got: [$obtained]")
   }
 
+  test("vararg function-type parameter") {
+    val code = "def b(x: Int => List[Int]*): Int = 2"
+    val tree = Defn.Def(
+      Nil,
+      "b",
+      Nil,
+      List(List(tparam("x", Type.Repeated(pfunc("Int")(papply("List", "Int")))))),
+      Some("Int"),
+      lit(2)
+    )
+    check(code)(tree)
+  }
+
 }