summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2012-03-19 18:26:55 -0700
committerPaul Phillips <paulp@improving.org>2012-03-19 20:13:36 -0700
commitc82ecabad6fc050411495f3fd50c3bf79ac7e96e (patch)
treee6498f4f2843bd14e16de365079601093af1abb5
parent4f565de67fcaf3818c1bcbe204e254014077e1de (diff)
downloadscala-c82ecabad6fc050411495f3fd50c3bf79ac7e96e.tar.gz
scala-c82ecabad6fc050411495f3fd50c3bf79ac7e96e.tar.bz2
scala-c82ecabad6fc050411495f3fd50c3bf79ac7e96e.zip
Finally did something about broken irrefutability.
The parser has always been confused about tuple patterns in for comprehensions. It thinks it can fail to recognize an irrefutable pattern and have it removed in refchecks, but it is sadly mistaken, because the unnecessary filter has a tendency to fail the compile in typer. Look more intently for irrefutable patterns and don't insert the unnecessary filter. Closes SI-5589, SI-1336.
-rw-r--r--src/compiler/scala/reflect/internal/TreeInfo.scala20
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala34
-rw-r--r--test/files/neg/t5589neg.check30
-rw-r--r--test/files/neg/t5589neg.scala28
-rw-r--r--test/files/pos/t1336.scala10
-rw-r--r--test/files/pos/t5589.scala22
6 files changed, 124 insertions, 20 deletions
diff --git a/src/compiler/scala/reflect/internal/TreeInfo.scala b/src/compiler/scala/reflect/internal/TreeInfo.scala
index 769d7a9ed1..ce3de94335 100644
--- a/src/compiler/scala/reflect/internal/TreeInfo.scala
+++ b/src/compiler/scala/reflect/internal/TreeInfo.scala
@@ -17,7 +17,7 @@ abstract class TreeInfo {
val global: SymbolTable
import global._
- import definitions.{ isVarArgsList, isCastSymbol, ThrowableClass }
+ import definitions.{ isVarArgsList, isCastSymbol, ThrowableClass, TupleClass }
/* Does not seem to be used. Not sure what it does anyway.
def isOwnerDefinition(tree: Tree): Boolean = tree match {
@@ -312,6 +312,24 @@ abstract class TreeInfo {
case _ => false
}
+ /** Is this tree comprised of nothing but identifiers,
+ * but possibly in bindings or tuples? For instance
+ *
+ * foo @ (bar, (baz, quux))
+ *
+ * is a variable pattern; if the structure matches,
+ * then the remainder is inevitable.
+ */
+ def isVariablePattern(tree: Tree): Boolean = tree match {
+ case Bind(name, pat) => isVariablePattern(pat)
+ case Ident(name) => true
+ case Apply(sel, args) =>
+ ( isReferenceToScalaMember(sel, TupleClass(args.size).name.toTermName)
+ && (args forall isVariablePattern)
+ )
+ case _ => false
+ }
+
/** Is this argument node of the form <expr> : _* ?
*/
def isWildcardStarArg(tree: Tree): Boolean = tree match {
diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
index 0d2fbc5372..80c258e456 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
@@ -262,29 +262,25 @@ abstract class TreeBuilder {
else if (stats.length == 1) stats.head
else Block(stats.init, stats.last)
+ def makeFilter(tree: Tree, condition: Tree, scrutineeName: String): Tree = {
+ val cases = List(
+ CaseDef(condition, EmptyTree, Literal(Constant(true))),
+ CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(false)))
+ )
+ val matchTree = makeVisitor(cases, false, scrutineeName)
+
+ atPos(tree.pos)(Apply(Select(tree, nme.filter), matchTree :: Nil))
+ }
+
/** Create tree for for-comprehension generator <val pat0 <- rhs0> */
def makeGenerator(pos: Position, pat: Tree, valeq: Boolean, rhs: Tree): Enumerator = {
val pat1 = patvarTransformer.transform(pat)
val rhs1 =
- if (valeq) rhs
- else matchVarPattern(pat1) match {
- case Some(_) =>
- rhs
- case None =>
- atPos(rhs.pos) {
- Apply(
- Select(rhs, nme.filter),
- List(
- makeVisitor(
- List(
- CaseDef(pat1.duplicate, EmptyTree, Literal(Constant(true))),
- CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(false)))),
- false,
- nme.CHECK_IF_REFUTABLE_STRING
- )))
- }
- }
- if (valeq) ValEq(pos, pat1, rhs1) else ValFrom(pos, pat1, rhs1)
+ if (valeq || treeInfo.isVariablePattern(pat)) rhs
+ else makeFilter(rhs, pat1.duplicate, nme.CHECK_IF_REFUTABLE_STRING)
+
+ if (valeq) ValEq(pos, pat1, rhs1)
+ else ValFrom(pos, pat1, rhs1)
}
def makeParam(pname: TermName, tpe: Tree) =
diff --git a/test/files/neg/t5589neg.check b/test/files/neg/t5589neg.check
new file mode 100644
index 0000000000..e75fd2f4f7
--- /dev/null
+++ b/test/files/neg/t5589neg.check
@@ -0,0 +1,30 @@
+t5589neg.scala:24: error: constructor cannot be instantiated to expected type;
+ found : (T1, T2)
+ required: String
+ def f5(x: Either[Int, String]) = for ((y1, y2: String) <- x.right) yield ((y1, y2))
+ ^
+t5589neg.scala:25: error: constructor cannot be instantiated to expected type;
+ found : (T1, T2)
+ required: String
+ def f6(x: Either[Int, String]) = for ((y1, y2: Any) <- x.right) yield ((y1, y2))
+ ^
+t5589neg.scala:26: error: constructor cannot be instantiated to expected type;
+ found : (T1,)
+ required: (String, Int)
+ def f7(x: Either[Int, (String, Int)]) = for (y1 @ Tuple1(y2) <- x.right) yield ((y1, y2))
+ ^
+t5589neg.scala:26: error: not found: value y2
+ def f7(x: Either[Int, (String, Int)]) = for (y1 @ Tuple1(y2) <- x.right) yield ((y1, y2))
+ ^
+t5589neg.scala:27: error: constructor cannot be instantiated to expected type;
+ found : (T1, T2, T3)
+ required: (String, Int)
+ def f8(x: Either[Int, (String, Int)]) = for ((y1, y2, y3) <- x.right) yield ((y1, y2))
+ ^
+t5589neg.scala:27: error: not found: value y1
+ def f8(x: Either[Int, (String, Int)]) = for ((y1, y2, y3) <- x.right) yield ((y1, y2))
+ ^
+t5589neg.scala:27: error: not found: value y2
+ def f8(x: Either[Int, (String, Int)]) = for ((y1, y2, y3) <- x.right) yield ((y1, y2))
+ ^
+7 errors found
diff --git a/test/files/neg/t5589neg.scala b/test/files/neg/t5589neg.scala
new file mode 100644
index 0000000000..ddd382d8d8
--- /dev/null
+++ b/test/files/neg/t5589neg.scala
@@ -0,0 +1,28 @@
+class A {
+ // First three compile.
+ def f1(x: Either[Int, String]) = x.right map (y => y)
+ def f2(x: Either[Int, String]) = for (y <- x.right) yield y
+ def f3(x: Either[Int, (String, Int)]) = x.right map { case (y1, y2) => (y1, y2) }
+ // Last one fails.
+ def f4(x: Either[Int, (String, Int)]) = for ((y1, y2) <- x.right) yield ((y1, y2))
+/**
+./a.scala:5: error: constructor cannot be instantiated to expected type;
+ found : (T1, T2)
+ required: Either[Nothing,(String, Int)]
+ def f4(x: Either[Int, (String, Int)]) = for ((y1, y2) <- x.right) yield ((y1, y2))
+ ^
+./a.scala:5: error: not found: value y1
+ def f4(x: Either[Int, (String, Int)]) = for ((y1, y2) <- x.right) yield ((y1, y2))
+ ^
+./a.scala:5: error: not found: value y2
+ def f4(x: Either[Int, (String, Int)]) = for ((y1, y2) <- x.right) yield ((y1, y2))
+ ^
+three errors found
+**/
+
+
+ def f5(x: Either[Int, String]) = for ((y1, y2: String) <- x.right) yield ((y1, y2))
+ def f6(x: Either[Int, String]) = for ((y1, y2: Any) <- x.right) yield ((y1, y2))
+ def f7(x: Either[Int, (String, Int)]) = for (y1 @ Tuple1(y2) <- x.right) yield ((y1, y2))
+ def f8(x: Either[Int, (String, Int)]) = for ((y1, y2, y3) <- x.right) yield ((y1, y2))
+}
diff --git a/test/files/pos/t1336.scala b/test/files/pos/t1336.scala
new file mode 100644
index 0000000000..63967985c7
--- /dev/null
+++ b/test/files/pos/t1336.scala
@@ -0,0 +1,10 @@
+object Foo {
+ def foreach( f : ((Int,Int)) => Unit ) {
+ println("foreach")
+ f(1,2)
+ }
+
+ for( (a,b) <- this ) {
+ println((a,b))
+ }
+}
diff --git a/test/files/pos/t5589.scala b/test/files/pos/t5589.scala
new file mode 100644
index 0000000000..69cbb20391
--- /dev/null
+++ b/test/files/pos/t5589.scala
@@ -0,0 +1,22 @@
+class A {
+ // First three compile.
+ def f1(x: Either[Int, String]) = x.right map (y => y)
+ def f2(x: Either[Int, String]) = for (y <- x.right) yield y
+ def f3(x: Either[Int, (String, Int)]) = x.right map { case (y1, y2) => (y1, y2) }
+ // Last one fails.
+ def f4(x: Either[Int, (String, Int)]) = for ((y1, y2) <- x.right) yield ((y1, y2))
+/**
+./a.scala:5: error: constructor cannot be instantiated to expected type;
+ found : (T1, T2)
+ required: Either[Nothing,(String, Int)]
+ def f4(x: Either[Int, (String, Int)]) = for ((y1, y2) <- x.right) yield ((y1, y2))
+ ^
+./a.scala:5: error: not found: value y1
+ def f4(x: Either[Int, (String, Int)]) = for ((y1, y2) <- x.right) yield ((y1, y2))
+ ^
+./a.scala:5: error: not found: value y2
+ def f4(x: Either[Int, (String, Int)]) = for ((y1, y2) <- x.right) yield ((y1, y2))
+ ^
+three errors found
+**/
+}