Skip to content

Commit 5fd7a95

Browse files
mielientievfelixmulder
authored andcommitted
Fix varargs in methods and constructors (#2135)
* Fix varargs in methods (Issue: #1625) * Fix minor comments * Change varargs parameter message * Fix failed test, fix case for constructor
1 parent 3af0ebb commit 5fd7a95

File tree

10 files changed

+57
-1
lines changed

10 files changed

+57
-1
lines changed

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,15 @@ 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+
2324
import scala.annotation.{tailrec, switch}
2425
import util.DotClass
2526
import rewrite.Rewrites.patch
@@ -1800,6 +1801,10 @@ object Parsers {
18001801
case _ => syntaxError(AuxConstructorNeedsNonImplicitParameter(), start)
18011802
}
18021803
}
1804+
val listOfErrors = checkVarArgsRules(result)
1805+
listOfErrors.foreach { vparam =>
1806+
syntaxError(VarArgsParamMustComeLast(), vparam.tpt.pos)
1807+
}
18031808
result
18041809
}
18051810

@@ -1921,6 +1926,21 @@ object Parsers {
19211926
}
19221927
}
19231928

1929+
1930+
1931+
private def checkVarArgsRules(vparamss: List[List[untpd.ValDef]]): List[untpd.ValDef] = {
1932+
def isVarArgs(tpt: Trees.Tree[Untyped]): Boolean = tpt match {
1933+
case PostfixOp(_, op) if op.name == nme.raw.STAR => true
1934+
case _ => false
1935+
}
1936+
1937+
vparamss.flatMap { params =>
1938+
if (params.nonEmpty) {
1939+
params.init.filter(valDef => isVarArgs(valDef.tpt))
1940+
} else List()
1941+
}
1942+
}
1943+
19241944
/** DefDef ::= DefSig (`:' Type [`=' Expr] | "=" Expr)
19251945
* | this ParamClause ParamClauses `=' ConstrExpr
19261946
* DefDcl ::= DefSig `:' Type

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 = "varargs 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 posVarargsT1625 = 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 negVarargsT1625 = 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: varargs parameter must come last
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
object T5 {
2+
case class Abc(x: String*, c: String*) // error //error: varargs parameter must come last AND found: String* required: String
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class Abc(val x: String*, val c: String*) { // error: varargs parameter must come last
2+
def test = ???
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: varargs 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: varargs 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)