Skip to content

Commit 1b28a05

Browse files
committed
Fix varargs in methods (Issue: scala#1625)
1 parent 3af0ebb commit 1b28a05

File tree

8 files changed

+53
-3
lines changed

8 files changed

+53
-3
lines changed

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,24 @@ package parsing
44

55
import scala.collection.mutable.ListBuffer
66
import scala.collection.immutable.BitSet
7-
import util.{ SourceFile, SourcePosition }
7+
import util.{SourceFile, SourcePosition}
88
import Tokens._
99
import Scanners._
1010
import MarkupParsers._
1111
import core._
1212
import Flags._
1313
import Contexts._
1414
import Names._
15-
import ast.Positioned
15+
import ast.{Positioned, Trees, untpd}
1616
import ast.Trees._
1717
import Decorators._
1818
import StdNames._
1919
import util.Positions._
2020
import Constants._
2121
import ScriptParsers._
2222
import Comments._
23-
import scala.annotation.{tailrec, switch}
23+
24+
import scala.annotation.{switch, tailrec}
2425
import util.DotClass
2526
import rewrite.Rewrites.patch
2627

@@ -1921,6 +1922,21 @@ object Parsers {
19211922
}
19221923
}
19231924

1925+
1926+
1927+
private def checkVarArgsRules(vparamss: List[List[untpd.ValDef]]): List[untpd.ValDef] = {
1928+
def isVarArgs(tpt: Trees.Tree[Untyped]): Boolean = tpt match {
1929+
case PostfixOp(_, op) if op.name == nme.raw.STAR => true
1930+
case _ => false
1931+
}
1932+
1933+
vparamss.flatMap { params =>
1934+
if (params.nonEmpty) {
1935+
params.init.filter(valDef => isVarArgs(valDef.tpt))
1936+
} else List()
1937+
}
1938+
}
1939+
19241940
/** DefDef ::= DefSig (`:' Type [`=' Expr] | "=" Expr)
19251941
* | this ParamClause ParamClauses `=' ConstrExpr
19261942
* DefDcl ::= DefSig `:' Type
@@ -1950,6 +1966,10 @@ object Parsers {
19501966
val name = ident()
19511967
val tparams = typeParamClauseOpt(ParamOwner.Def)
19521968
val vparamss = paramClauses(name)
1969+
val listOfErrors = checkVarArgsRules(vparamss)
1970+
listOfErrors.foreach { vparam =>
1971+
syntaxError(VarArgsParamMustComeLast(), vparam.tpt.pos)
1972+
}
19531973
var tpt = fromWithinReturnType(typedOpt())
19541974
if (in.isScala2Mode) newLineOptWhenFollowedBy(LBRACE)
19551975
val rhs =

compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1209,4 +1209,16 @@ object messages {
12091209
|${parents.mkString(" - ", "\n - ", "")}
12101210
|""".stripMargin
12111211
}
1212+
1213+
case class VarArgsParamMustComeLast()(implicit ctx: Context)
1214+
extends Message(IncorrectRepeatedParameterSyntaxID) {
1215+
override def msg: String = "*-parameter must come last"
1216+
1217+
override def kind: String = "Syntax"
1218+
1219+
override def explanation: String =
1220+
hl"""|The varargs field must be the last field in the method signature.
1221+
|Attempting to define a field in a method signature after a varargs field is an error.
1222+
|""".stripMargin
1223+
}
12121224
}

compiler/test/dotc/tests.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ class tests extends CompilerTest {
153153
@Test def pos_anonClassSubtyping = compileFile(posDir, "anonClassSubtyping", twice)
154154
@Test def pos_extmethods = compileFile(posDir, "extmethods", twice)
155155
@Test def pos_companions = compileFile(posDir, "companions", twice)
156+
@Test def posVarargsInMethodsT1625 = compileFiles(posDir + "varargsInMethodsT1625/")
156157

157158
@Test def pos_all = compileFiles(posDir) // twice omitted to make tests run faster
158159

@@ -177,6 +178,8 @@ class tests extends CompilerTest {
177178
@Test def neg_all = compileFiles(negDir, verbose = true, compileSubDirs = false)
178179
@Test def neg_typedIdents() = compileDir(negDir, "typedIdents")
179180

181+
@Test def negVarargsInMethodsT1625 = compileFiles(negDir + "varargsInMethodsT1625/")
182+
180183
val negCustomArgs = negDir + "customArgs/"
181184

182185
@Test def neg_typers() = compileFile(negCustomArgs, "typers")(allowDoubleBindings)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
trait T3 {
2+
def foo(x: String*, y: String*, c: String*): Int // error // error: *-parameter must come last
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
trait T2 {
2+
def foo(x: String*, y: String*)(z: Boolean*)(u: Int*, l: Int*): Int // error // error: *-parameter must come last
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
trait T1 {
2+
def foo(x: String*, y: String): Int // error: *-parameter must come last
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
trait T2 {
2+
def foo(x: String, y: String*)(z: Boolean*)(u: Int, l: Int*): Int
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
trait T1 {
2+
def foo(x: String*): Int
3+
}

0 commit comments

Comments
 (0)