diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala | 2 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/TreeInfo.scala | 80 | ||||
-rw-r--r-- | test/files/run/t6646.check | 5 | ||||
-rw-r--r-- | test/files/run/t6646.scala | 19 | ||||
-rwxr-xr-x | tools/epfl-publish | 2 |
5 files changed, 88 insertions, 20 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index 0d13623e0c..0ac46a18bc 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -285,7 +285,7 @@ abstract class TreeBuilder { def makeGenerator(pos: Position, pat: Tree, valeq: Boolean, rhs: Tree): Enumerator = { val pat1 = patvarTransformer.transform(pat) val rhs1 = - if (valeq || treeInfo.isVariablePattern(pat)) rhs + if (valeq || treeInfo.isVarPatternDeep(pat)) rhs else makeFilter(rhs, pat1.duplicate, nme.CHECK_IF_REFUTABLE_STRING) if (valeq) ValEq(pos, pat1, rhs1) diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 38e55a3c01..8ad15f37e4 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -245,6 +245,68 @@ abstract class TreeInfo { isSelfConstrCall(tree1) || isSuperConstrCall(tree1) } + /** + * Does this tree represent an irrefutable pattern match + * in the position `for { <tree> <- expr }` based only + * on information at the `parser` phase? To qualify, there + * may be no subtree that will be interpreted as a + * Stable Identifier Pattern. + * + * For instance: + * + * {{{ + * foo @ (bar, (baz, quux)) + * }}} + * + * is a variable pattern; if the structure matches, + * then the remainder is inevitable. + * + * The following are not variable patterns. + * + * {{{ + * foo @ (bar, (`baz`, quux)) // back quoted ident, not at top level + * foo @ (bar, Quux) // UpperCase ident, not at top level + * }}} + * + * If the pattern is a simple identifier, it is always + * a variable pattern. For example, the following + * introduce new bindings: + * + * {{{ + * for { X <- xs } yield X + * for { `backquoted` <- xs } yield `backquoted` + * }}} + * + * Note that this differs from a case clause: + * + * {{{ + * object X + * scrut match { + * case X => // case _ if scrut == X + * } + * }}} + * + * Background: [[https://groups.google.com/d/msg/scala-internals/qwa_XOw_7Ks/IktkeTBYqg0J]] + * + */ + def isVarPatternDeep(tree: Tree): Boolean = { + def isVarPatternDeep0(tree: Tree): Boolean = { + tree match { + case Bind(name, pat) => isVarPatternDeep0(pat) + case Ident(name) => isVarPattern(tree) + case Apply(sel, args) => + ( isReferenceToScalaMember(sel, TupleClass(args.size).name.toTermName) + && (args forall isVarPatternDeep0) + ) + case _ => false + } + } + tree match { + case Ident(name) => true + case _ => isVarPatternDeep0(tree) + } + } + /** Is tree a variable pattern? */ def isVarPattern(pat: Tree): Boolean = pat match { case x: Ident => !x.isBackquoted && nme.isVariableName(x.name) @@ -330,24 +392,6 @@ 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/test/files/run/t6646.check b/test/files/run/t6646.check new file mode 100644 index 0000000000..b0b7ad32f3 --- /dev/null +++ b/test/files/run/t6646.check @@ -0,0 +1,5 @@ +Found NotNull +Found lower +Found 2 +A single ident is always a pattern +A single ident is always a pattern diff --git a/test/files/run/t6646.scala b/test/files/run/t6646.scala new file mode 100644 index 0000000000..150b0df11e --- /dev/null +++ b/test/files/run/t6646.scala @@ -0,0 +1,19 @@ +sealed trait ColumnOption +case object NotNull extends ColumnOption +case object PrimaryKey extends ColumnOption +case object lower extends ColumnOption + +object Test { + def main(args: Array[String]) { + val l = List(PrimaryKey, NotNull, lower) + + // withFilter must be generated in these + for (option @ NotNull <- l) println("Found " + option) + for (option @ `lower` <- l) println("Found " + option) + for ((`lower`, i) <- l.zipWithIndex) println("Found " + i) + + // no withFilter + for (X <- List("A single ident is always a pattern")) println(X) + for (`x` <- List("A single ident is always a pattern")) println(`x`) + } +} diff --git a/tools/epfl-publish b/tools/epfl-publish index de5e17b13f..cdf18823a5 100755 --- a/tools/epfl-publish +++ b/tools/epfl-publish @@ -24,7 +24,7 @@ if [[ -z $publish_to ]]; then else echo "Publishing nightly build to $publish_to" # Archive Scala nightly distribution - rsync -az dists/archives/ "$publish_to/distributions" + rsync -az --exclude scala-latest-sources.tgz dists/archives/ "$publish_to/distributions" # only publish scaladoc nightly for trunk [[ $version == "master" ]] && rsync -az build/scaladoc/ "$publish_to/docs" # sbaz |