summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala13
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala23
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala16
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala4
-rw-r--r--src/reflect/scala/reflect/internal/util/Collections.scala5
-rw-r--r--test/files/neg/missing-param-type-tuple.check31
-rw-r--r--test/files/neg/missing-param-type-tuple.scala8
-rw-r--r--test/files/neg/not-a-legal-formal-parameter-tuple.check19
-rw-r--r--test/files/neg/not-a-legal-formal-parameter-tuple.scala5
10 files changed, 119 insertions, 8 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index 0429e295b4..91db1bb92a 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -732,6 +732,7 @@ self =>
def removeAsPlaceholder(name: Name) {
placeholderParams = placeholderParams filter (_.name != name)
}
+ def errorParam = makeParam(nme.ERROR, errorTypeTree setPos o2p(tree.pos.end))
tree match {
case Ident(name) =>
removeAsPlaceholder(name)
@@ -739,9 +740,19 @@ self =>
case Typed(Ident(name), tpe) if tpe.isType => // get the ident!
removeAsPlaceholder(name)
makeParam(name.toTermName, tpe)
+ case build.SyntacticTuple(as) =>
+ val arity = as.length
+ val example = analyzer.exampleTuplePattern(as map { case Ident(name) => name; case _ => nme.EMPTY })
+ val msg =
+ sm"""|not a legal formal parameter.
+ |Note: Tuples cannot be directly destructured in method or function parameters.
+ | Either create a single parameter accepting the Tuple${arity},
+ | or consider a pattern matching anonymous function: `{ case $example => ... }"""
+ syntaxError(tree.pos, msg, skipIt = false)
+ errorParam
case _ =>
syntaxError(tree.pos, "not a legal formal parameter", skipIt = false)
- makeParam(nme.ERROR, errorTypeTree setPos o2p(tree.pos.end))
+ errorParam
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala
index 45698c0c76..8ff7824159 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala
@@ -233,9 +233,6 @@ trait MatchOptimization extends MatchTreeMaking with MatchAnalysis {
def defaultBody: Tree
def defaultCase(scrutSym: Symbol = defaultSym, guard: Tree = EmptyTree, body: Tree = defaultBody): CaseDef
- private def sequence[T](xs: List[Option[T]]): Option[List[T]] =
- if (xs exists (_.isEmpty)) None else Some(xs.flatten)
-
object GuardAndBodyTreeMakers {
def unapply(tms: List[TreeMaker]): Option[(Tree, Tree)] = {
tms match {
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index 7ecc2be9be..2472f63993 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -408,11 +408,28 @@ trait ContextErrors {
setError(tree)
}
- def MissingParameterTypeError(fun: Tree, vparam: ValDef, pt: Type) =
+ def MissingParameterTypeError(fun: Tree, vparam: ValDef, pt: Type, withTupleAddendum: Boolean) = {
+ def issue(what: String) = {
+ val addendum: String = fun match {
+ case Function(params, _) if withTupleAddendum =>
+ val funArity = params.length
+ val example = analyzer.exampleTuplePattern(params map (_.name))
+ (pt baseType FunctionClass(1)) match {
+ case TypeRef(_, _, arg :: _) if arg.typeSymbol == TupleClass(funArity) && funArity > 1 =>
+ sm"""|
+ |Note: The expected type requires a one-argument function accepting a $funArity-Tuple.
+ | Consider a pattern matching anoynmous function, `{ case $example => ... }`"""
+ case _ => ""
+ }
+ case _ => ""
+ }
+ issueNormalTypeError(vparam, what + addendum)
+ }
if (vparam.mods.isSynthetic) fun match {
case Function(_, Match(_, _)) => MissingParameterTypeAnonMatchError(vparam, pt)
- case _ => issueNormalTypeError(vparam, "missing parameter type for expanded function " + fun)
- } else issueNormalTypeError(vparam, "missing parameter type")
+ case _ => issue("missing parameter type for expanded function " + fun)
+ } else issue("missing parameter type")
+ }
def MissingParameterTypeAnonMatchError(vparam: Tree, pt: Type) =
issueNormalTypeError(vparam, "missing parameter type for expanded function\n"+
diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
index 695a1e2e24..b801b644fb 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
@@ -109,6 +109,22 @@ trait TypeDiagnostics {
case x => x.toString
}
+ /**
+ * [a, b, c] => "(a, b, c)"
+ * [a, B] => "(param1, param2)"
+ * [a, B, c] => "(param1, ..., param2)"
+ */
+ final def exampleTuplePattern(names: List[Name]): String = {
+ val arity = names.length
+ val varPatterNames: Option[List[String]] = sequence(names map {
+ case name if nme.isVariableName(name) => Some(name.decode)
+ case _ => None
+ })
+ def parenthesize(a: String) = s"($a)"
+ def genericParams = (Seq("param1") ++ (if (arity > 2) Seq("...") else Nil) ++ Seq(s"param$arity"))
+ parenthesize(varPatterNames.getOrElse(genericParams).mkString(", "))
+ }
+
def alternatives(tree: Tree): List[Type] = tree.tpe match {
case OverloadedType(pre, alternatives) => alternatives map pre.memberType
case _ => Nil
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 6d799b0098..4973346eff 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -2906,6 +2906,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
else if (argpts.lengthCompare(numVparams) != 0)
WrongNumberOfParametersError(fun, argpts)
else {
+ var issuedMissingParameterTypeError = false
foreach2(fun.vparams, argpts) { (vparam, argpt) =>
if (vparam.tpt.isEmpty) {
vparam.tpt.tpe =
@@ -2923,7 +2924,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}
case _ =>
}
- MissingParameterTypeError(fun, vparam, pt)
+ MissingParameterTypeError(fun, vparam, pt, withTupleAddendum = !issuedMissingParameterTypeError)
+ issuedMissingParameterTypeError = true
ErrorType
}
if (!vparam.tpt.pos.isDefined) vparam.tpt setPos vparam.pos.focus
diff --git a/src/reflect/scala/reflect/internal/util/Collections.scala b/src/reflect/scala/reflect/internal/util/Collections.scala
index 738baddc08..7cc2952c96 100644
--- a/src/reflect/scala/reflect/internal/util/Collections.scala
+++ b/src/reflect/scala/reflect/internal/util/Collections.scala
@@ -244,6 +244,11 @@ trait Collections {
true
}
+ final def sequence[A](as: List[Option[A]]): Option[List[A]] = {
+ if (as.exists (_.isEmpty)) None
+ else Some(as.flatten)
+ }
+
final def transposeSafe[A](ass: List[List[A]]): Option[List[List[A]]] = try {
Some(ass.transpose)
} catch {
diff --git a/test/files/neg/missing-param-type-tuple.check b/test/files/neg/missing-param-type-tuple.check
new file mode 100644
index 0000000000..bc46ba1023
--- /dev/null
+++ b/test/files/neg/missing-param-type-tuple.check
@@ -0,0 +1,31 @@
+missing-param-type-tuple.scala:3: error: missing parameter type
+Note: The expected type requires a one-argument function accepting a 2-Tuple.
+ Consider a pattern matching anoynmous function, `{ case (a, b) => ... }`
+ val x: ((Int, Int)) => Int = (a, b) => 0
+ ^
+missing-param-type-tuple.scala:3: error: missing parameter type
+ val x: ((Int, Int)) => Int = (a, b) => 0
+ ^
+missing-param-type-tuple.scala:5: error: missing parameter type
+Note: The expected type requires a one-argument function accepting a 3-Tuple.
+ Consider a pattern matching anoynmous function, `{ case (param1, ..., param3) => ... }`
+ val y: ((Int, Int, Int)) => Int = (a, b, !!) => 0
+ ^
+missing-param-type-tuple.scala:5: error: missing parameter type
+ val y: ((Int, Int, Int)) => Int = (a, b, !!) => 0
+ ^
+missing-param-type-tuple.scala:5: error: missing parameter type
+ val y: ((Int, Int, Int)) => Int = (a, b, !!) => 0
+ ^
+missing-param-type-tuple.scala:7: error: missing parameter type
+Note: The expected type requires a one-argument function accepting a 3-Tuple.
+ Consider a pattern matching anoynmous function, `{ case (param1, ..., param3) => ... }`
+ val z: ((Int, Int, Int)) => Int = (a, NotAVariablePatternName, c) => 0
+ ^
+missing-param-type-tuple.scala:7: error: missing parameter type
+ val z: ((Int, Int, Int)) => Int = (a, NotAVariablePatternName, c) => 0
+ ^
+missing-param-type-tuple.scala:7: error: missing parameter type
+ val z: ((Int, Int, Int)) => Int = (a, NotAVariablePatternName, c) => 0
+ ^
+8 errors found
diff --git a/test/files/neg/missing-param-type-tuple.scala b/test/files/neg/missing-param-type-tuple.scala
new file mode 100644
index 0000000000..72c0c82034
--- /dev/null
+++ b/test/files/neg/missing-param-type-tuple.scala
@@ -0,0 +1,8 @@
+class C {
+
+ val x: ((Int, Int)) => Int = (a, b) => 0
+
+ val y: ((Int, Int, Int)) => Int = (a, b, !!) => 0
+
+ val z: ((Int, Int, Int)) => Int = (a, NotAVariablePatternName, c) => 0
+}
diff --git a/test/files/neg/not-a-legal-formal-parameter-tuple.check b/test/files/neg/not-a-legal-formal-parameter-tuple.check
new file mode 100644
index 0000000000..2b906b8ff3
--- /dev/null
+++ b/test/files/neg/not-a-legal-formal-parameter-tuple.check
@@ -0,0 +1,19 @@
+not-a-legal-formal-parameter-tuple.scala:2: error: not a legal formal parameter.
+Note: Tuples cannot be directly destructured in method or function parameters.
+ Either create a single parameter accepting the Tuple2,
+ or consider a pattern matching anonymous function: `{ case (a, b) => ... }
+ val x: ((Int, Int) => Int) = (((a, b)) => a)
+ ^
+not-a-legal-formal-parameter-tuple.scala:3: error: not a legal formal parameter.
+Note: Tuples cannot be directly destructured in method or function parameters.
+ Either create a single parameter accepting the Tuple2,
+ or consider a pattern matching anonymous function: `{ case (param1, param2) => ... }
+ val y: ((Int, Int, Int) => Int) = (((a, !!)) => a)
+ ^
+not-a-legal-formal-parameter-tuple.scala:4: error: not a legal formal parameter.
+Note: Tuples cannot be directly destructured in method or function parameters.
+ Either create a single parameter accepting the Tuple3,
+ or consider a pattern matching anonymous function: `{ case (param1, ..., param3) => ... }
+ val z: ((Int, Int, Int) => Int) = (((a, NotAPatternVariableName, c)) => a)
+ ^
+three errors found
diff --git a/test/files/neg/not-a-legal-formal-parameter-tuple.scala b/test/files/neg/not-a-legal-formal-parameter-tuple.scala
new file mode 100644
index 0000000000..c7a13557df
--- /dev/null
+++ b/test/files/neg/not-a-legal-formal-parameter-tuple.scala
@@ -0,0 +1,5 @@
+class C {
+ val x: ((Int, Int) => Int) = (((a, b)) => a)
+ val y: ((Int, Int, Int) => Int) = (((a, !!)) => a)
+ val z: ((Int, Int, Int) => Int) = (((a, NotAPatternVariableName, c)) => a)
+}