From 5fd7a9503e44b8e95c0ca5aa4366270a3cd90155 Mon Sep 17 00:00:00 2001 From: Igor Mielientiev Date: Wed, 22 Mar 2017 16:24:15 +0200 Subject: 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 --- .../src/dotty/tools/dotc/parsing/Parsers.scala | 22 +++++++++++++++++++++- .../tools/dotc/reporting/diagnostic/messages.scala | 12 ++++++++++++ compiler/test/dotc/tests.scala | 3 +++ .../allParamsAreVarArgs.scala | 3 +++ .../caseClassConstructorVarArgs.scala | 3 +++ .../classConstructorVarArgs.scala | 3 +++ .../varargsInMethodsT1625/curriedNegExample.scala | 3 +++ .../firstParamIsVarArgs.scala | 3 +++ .../varargsInMethodsT1625/curriedPosExample.scala | 3 +++ .../pos/varargsInMethodsT1625/onlyOneVarArgs.scala | 3 +++ 10 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 tests/neg/varargsInMethodsT1625/allParamsAreVarArgs.scala create mode 100644 tests/neg/varargsInMethodsT1625/caseClassConstructorVarArgs.scala create mode 100644 tests/neg/varargsInMethodsT1625/classConstructorVarArgs.scala create mode 100644 tests/neg/varargsInMethodsT1625/curriedNegExample.scala create mode 100644 tests/neg/varargsInMethodsT1625/firstParamIsVarArgs.scala create mode 100644 tests/pos/varargsInMethodsT1625/curriedPosExample.scala create mode 100644 tests/pos/varargsInMethodsT1625/onlyOneVarArgs.scala diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 65c7a290d..b644c94cc 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -12,7 +12,7 @@ import core._ import Flags._ import Contexts._ import Names._ -import ast.Positioned +import ast.{Positioned, Trees, untpd} import ast.Trees._ import Decorators._ import StdNames._ @@ -20,6 +20,7 @@ import util.Positions._ import Constants._ import ScriptParsers._ import Comments._ + import scala.annotation.{tailrec, switch} import util.DotClass import rewrite.Rewrites.patch @@ -1800,6 +1801,10 @@ object Parsers { case _ => syntaxError(AuxConstructorNeedsNonImplicitParameter(), start) } } + val listOfErrors = checkVarArgsRules(result) + listOfErrors.foreach { vparam => + syntaxError(VarArgsParamMustComeLast(), vparam.tpt.pos) + } result } @@ -1921,6 +1926,21 @@ object Parsers { } } + + + private def checkVarArgsRules(vparamss: List[List[untpd.ValDef]]): List[untpd.ValDef] = { + def isVarArgs(tpt: Trees.Tree[Untyped]): Boolean = tpt match { + case PostfixOp(_, op) if op.name == nme.raw.STAR => true + case _ => false + } + + vparamss.flatMap { params => + if (params.nonEmpty) { + params.init.filter(valDef => isVarArgs(valDef.tpt)) + } else List() + } + } + /** DefDef ::= DefSig (`:' Type [`=' Expr] | "=" Expr) * | this ParamClause ParamClauses `=' ConstrExpr * DefDcl ::= DefSig `:' Type diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 6fa056646..57365658e 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -1209,4 +1209,16 @@ object messages { |${parents.mkString(" - ", "\n - ", "")} |""".stripMargin } + + case class VarArgsParamMustComeLast()(implicit ctx: Context) + extends Message(IncorrectRepeatedParameterSyntaxID) { + override def msg: String = "varargs parameter must come last" + + override def kind: String = "Syntax" + + override def explanation: String = + hl"""|The varargs field must be the last field in the method signature. + |Attempting to define a field in a method signature after a varargs field is an error. + |""".stripMargin + } } diff --git a/compiler/test/dotc/tests.scala b/compiler/test/dotc/tests.scala index 01db2d9cc..3ebf7f2c4 100644 --- a/compiler/test/dotc/tests.scala +++ b/compiler/test/dotc/tests.scala @@ -153,6 +153,7 @@ class tests extends CompilerTest { @Test def pos_anonClassSubtyping = compileFile(posDir, "anonClassSubtyping", twice) @Test def pos_extmethods = compileFile(posDir, "extmethods", twice) @Test def pos_companions = compileFile(posDir, "companions", twice) + @Test def posVarargsT1625 = compileFiles(posDir + "varargsInMethodsT1625/") @Test def pos_all = compileFiles(posDir) // twice omitted to make tests run faster @@ -177,6 +178,8 @@ class tests extends CompilerTest { @Test def neg_all = compileFiles(negDir, verbose = true, compileSubDirs = false) @Test def neg_typedIdents() = compileDir(negDir, "typedIdents") + @Test def negVarargsT1625 = compileFiles(negDir + "varargsInMethodsT1625/") + val negCustomArgs = negDir + "customArgs/" @Test def neg_typers() = compileFile(negCustomArgs, "typers")(allowDoubleBindings) diff --git a/tests/neg/varargsInMethodsT1625/allParamsAreVarArgs.scala b/tests/neg/varargsInMethodsT1625/allParamsAreVarArgs.scala new file mode 100644 index 000000000..aabb1ecea --- /dev/null +++ b/tests/neg/varargsInMethodsT1625/allParamsAreVarArgs.scala @@ -0,0 +1,3 @@ +trait T3 { + def foo(x: String*, y: String*, c: String*): Int // error // error: varargs parameter must come last +} \ No newline at end of file diff --git a/tests/neg/varargsInMethodsT1625/caseClassConstructorVarArgs.scala b/tests/neg/varargsInMethodsT1625/caseClassConstructorVarArgs.scala new file mode 100644 index 000000000..8f8a4fcf6 --- /dev/null +++ b/tests/neg/varargsInMethodsT1625/caseClassConstructorVarArgs.scala @@ -0,0 +1,3 @@ +object T5 { + case class Abc(x: String*, c: String*) // error //error: varargs parameter must come last AND found: String* required: String +} \ No newline at end of file diff --git a/tests/neg/varargsInMethodsT1625/classConstructorVarArgs.scala b/tests/neg/varargsInMethodsT1625/classConstructorVarArgs.scala new file mode 100644 index 000000000..74595cb7d --- /dev/null +++ b/tests/neg/varargsInMethodsT1625/classConstructorVarArgs.scala @@ -0,0 +1,3 @@ +class Abc(val x: String*, val c: String*) { // error: varargs parameter must come last + def test = ??? +} \ No newline at end of file diff --git a/tests/neg/varargsInMethodsT1625/curriedNegExample.scala b/tests/neg/varargsInMethodsT1625/curriedNegExample.scala new file mode 100644 index 000000000..616ea0539 --- /dev/null +++ b/tests/neg/varargsInMethodsT1625/curriedNegExample.scala @@ -0,0 +1,3 @@ +trait T2 { + def foo(x: String*, y: String*)(z: Boolean*)(u: Int*, l: Int*): Int // error // error: varargs parameter must come last +} \ No newline at end of file diff --git a/tests/neg/varargsInMethodsT1625/firstParamIsVarArgs.scala b/tests/neg/varargsInMethodsT1625/firstParamIsVarArgs.scala new file mode 100644 index 000000000..eceb7e696 --- /dev/null +++ b/tests/neg/varargsInMethodsT1625/firstParamIsVarArgs.scala @@ -0,0 +1,3 @@ +trait T1 { + def foo(x: String*, y: String): Int // error: varargs parameter must come last +} \ No newline at end of file diff --git a/tests/pos/varargsInMethodsT1625/curriedPosExample.scala b/tests/pos/varargsInMethodsT1625/curriedPosExample.scala new file mode 100644 index 000000000..c614f2dee --- /dev/null +++ b/tests/pos/varargsInMethodsT1625/curriedPosExample.scala @@ -0,0 +1,3 @@ +trait T2 { + def foo(x: String, y: String*)(z: Boolean*)(u: Int, l: Int*): Int +} \ No newline at end of file diff --git a/tests/pos/varargsInMethodsT1625/onlyOneVarArgs.scala b/tests/pos/varargsInMethodsT1625/onlyOneVarArgs.scala new file mode 100644 index 000000000..834960b4a --- /dev/null +++ b/tests/pos/varargsInMethodsT1625/onlyOneVarArgs.scala @@ -0,0 +1,3 @@ +trait T1 { + def foo(x: String*): Int +} \ No newline at end of file -- cgit v1.2.3