From b9e3ea7f070806631fd318e43082bc0653a79410 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Tue, 13 Nov 2012 11:21:17 +0100 Subject: SI-6646 `ident` or Ident is always new binding. The previous commit regressed in these cases: // 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`) At the top level of the LHS of a <-, such identifiers represent new bindings, not stable identifier patterns. --- src/reflect/scala/reflect/internal/TreeInfo.scala | 84 ++++++++++++++++------- 1 file changed, 59 insertions(+), 25 deletions(-) (limited to 'src/reflect') diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 56a0bac72b..90f4f6fc8f 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -245,31 +245,65 @@ abstract class TreeInfo { isSelfConstrCall(tree1) || isSuperConstrCall(tree1) } - /** 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. - * - * The following are not variable patterns. - * - * {{{ - * foo @ (bar, (`baz`, Quux)) - * foo @ (bar, Quux) - * }}} - */ - def isVarPatternDeep(tree: Tree): Boolean = tree match { - case Bind(name, pat) => isVarPatternDeep(pat) - case Ident(name) => isVarPattern(tree) - case Apply(sel, args) => - ( isReferenceToScalaMember(sel, TupleClass(args.size).name.toTermName) - && (args forall isVarPatternDeep) - ) - case _ => false + /** + * Does this tree represent an irrefutable pattern match + * in the position `for { <- expr }` based only + * on information at the `parser` phase? To qualify, there + * may be no Stable Identifier Patterns. + * + * 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? */ -- cgit v1.2.3