From ce1bbfe5c6a06e7de69210fbedd5e4cae270510a Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Wed, 19 Sep 2012 01:01:15 -0700 Subject: Regex.unapplySeq should not take Any (Fixes SI-6406) This deprecates unapplySeq(Any) and adds overloaded unapplySeq(CharSequence) and unapplySeq(Match), with the putative advantage that you can't try to extract the unextractable. Regex is massaged so that the underlying Pattern is primary, rather than the String-valued expression. Regex and its unanchored companion (I almost wrote unmoored) share a Pattern object, so that unapplySeq(Match) can easily test whether the Match was generated by this Regex; in that case, the match result is used immediately, instead of reapplying the regex to the matched string. The documentation is massaged to reflect unanchored and also to align with the underlying terminology, e.g., "subgroup" really just means "group." --- src/library/scala/util/matching/Regex.scala | 98 +++++++++++++++++++---------- 1 file changed, 64 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/library/scala/util/matching/Regex.scala b/src/library/scala/util/matching/Regex.scala index 3655a0a019..63d049208a 100644 --- a/src/library/scala/util/matching/Regex.scala +++ b/src/library/scala/util/matching/Regex.scala @@ -131,7 +131,7 @@ import java.util.regex.{ Pattern, Matcher } * @author Martin Odersky * @version 1.1, 29/01/2008 * - * @param regex A string representing a regular expression + * @param pattern The compiled pattern * @param groupNames A mapping from names to indices in capture groups * * @define replacementString @@ -144,41 +144,67 @@ import java.util.regex.{ Pattern, Matcher } * to automatically escape these characters. */ @SerialVersionUID(-2094783597747625537L) -class Regex(regex: String, groupNames: String*) extends Serializable { +class Regex private[matching](val pattern: Pattern, groupNames: String*) extends Serializable { outer => import Regex._ - /** The compiled pattern */ - val pattern = Pattern.compile(regex) + /** + * @param regex A string representing a regular expression + * @param groupNames A mapping from names to indices in capture groups + */ + def this(regex: String, groupNames: String*) = this(Pattern.compile(regex), groupNames: _*) - /** Tries to match target (whole match) and returns the matching subgroups. - * if the pattern has no subgroups, then it returns an empty list on a - * successful match. - * - * Note, however, that if some subgroup has not been matched, a `null` will - * be returned for that subgroup. + /** Tries to match a [[java.lang.CharSequence]]. + * If the match succeeds, the result is a list of the matching + * groups (or a `null` element if a group did not match any input). + * If the pattern specifies no groups, then the result will be an empty list + * on a successful match. * + * This method attempts to match the entire input by default; to find the next + * matching subsequence, use an unanchored Regex. + * For example: * * {{{ * val p1 = "ab*c".r - * val p2 = "a(b*)c".r - * * val p1Matches = "abbbc" match { * case p1() => true * case _ => false * } - * + * val p2 = "a(b*)c".r * val numberOfB = "abbbc" match { * case p2(b) => Some(b.length) * case _ => None * } + * val p3 = "b*".r.unanchored + * val p3Matches = "abbbc" match { + * case p3() => true + * case _ => false + * } * }}} * - * @param target The string to match + * @param s The string to match * @return The matches */ + def unapplySeq(s: CharSequence): Option[Seq[String]] = { + val m = pattern matcher s + if (runMatcher(m)) Some(1 to m.groupCount map m.group) + else None + } + + /** Tries to match on a [[scala.util.matching.Regex.Match]]. + * A previously failed match results in None. + * If a successful match was made against the current pattern, then that result is used. + * Otherwise, this Regex is applied to the previously matched input, + * and the result of that match is used. + */ + def unapplySeq(m: Match): Option[Seq[String]] = + if (m.matched == null) None + else if (m.matcher.pattern == this.pattern) Some(1 to m.groupCount map m.group) + else unapplySeq(m.matched) + + @deprecated("Extracting a match result from anything but a CharSequence or Match is deprecated", "2.10.0") def unapplySeq(target: Any): Option[List[String]] = target match { case s: CharSequence => val m = pattern matcher s @@ -187,6 +213,8 @@ class Regex(regex: String, groupNames: String*) extends Serializable { case m: Match => unapplySeq(m.matched) case _ => None } + + // @see UnanchoredRegex protected def runMatcher(m: Matcher) = m.matches() /** Return all matches of this regexp in given character sequence as a [[scala.util.matching.Regex.MatchIterator]], @@ -200,7 +228,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable { * @return A [[scala.util.matching.Regex.MatchIterator]] of all matches. * @example {{{for (words <- """\w+""".r findAllIn "A simple example.") yield words}}} */ - def findAllIn(source: java.lang.CharSequence) = new Regex.MatchIterator(source, this, groupNames) + def findAllIn(source: CharSequence) = new Regex.MatchIterator(source, this, groupNames) /** Return all matches of this regexp in given character sequence as a @@ -210,7 +238,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable { * @return A [[scala.collection.Iterator]] of [[scala.util.matching.Regex.Match]] for all matches. * @example {{{for (words <- """\w+""".r findAllMatchIn "A simple example.") yield words.start}}} */ - def findAllMatchIn(source: java.lang.CharSequence): Iterator[Match] = { + def findAllMatchIn(source: CharSequence): Iterator[Match] = { val matchIterator = findAllIn(source) new Iterator[Match] { def hasNext = matchIterator.hasNext @@ -228,7 +256,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable { * @return An [[scala.Option]] of the first matching string in the text. * @example {{{"""\w+""".r findFirstIn "A simple example." foreach println // prints "A"}}} */ - def findFirstIn(source: java.lang.CharSequence): Option[String] = { + def findFirstIn(source: CharSequence): Option[String] = { val m = pattern.matcher(source) if (m.find) Some(m.group) else None } @@ -245,7 +273,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable { * @return A [[scala.Option]] of [[scala.util.matching.Regex.Match]] of the first matching string in the text. * @example {{{("""[a-z]""".r findFirstMatchIn "A simple example.") map (_.start) // returns Some(2), the index of the first match in the text}}} */ - def findFirstMatchIn(source: java.lang.CharSequence): Option[Match] = { + def findFirstMatchIn(source: CharSequence): Option[Match] = { val m = pattern.matcher(source) if (m.find) Some(new Match(source, m, groupNames)) else None } @@ -262,7 +290,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable { * @return A [[scala.Option]] of the matched prefix. * @example {{{"""[a-z]""".r findPrefixOf "A simple example." // returns None, since the text does not begin with a lowercase letter}}} */ - def findPrefixOf(source: java.lang.CharSequence): Option[String] = { + def findPrefixOf(source: CharSequence): Option[String] = { val m = pattern.matcher(source) if (m.lookingAt) Some(m.group) else None } @@ -279,7 +307,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable { * @return A [[scala.Option]] of the [[scala.util.matching.Regex.Match]] of the matched string. * @example {{{"""\w+""".r findPrefixMatchOf "A simple example." map (_.after) // returns Some(" simple example.")}}} */ - def findPrefixMatchOf(source: java.lang.CharSequence): Option[Match] = { + def findPrefixMatchOf(source: CharSequence): Option[Match] = { val m = pattern.matcher(source) if (m.lookingAt) Some(new Match(source, m, groupNames)) else None } @@ -293,7 +321,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable { * @return The resulting string * @example {{{"""\d+""".r replaceAllIn ("July 15", "") // returns "July "}}} */ - def replaceAllIn(target: java.lang.CharSequence, replacement: String): String = { + def replaceAllIn(target: CharSequence, replacement: String): String = { val m = pattern.matcher(target) m.replaceAll(replacement) } @@ -316,7 +344,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable { * @param replacer The function which maps a match to another string. * @return The target string after replacements. */ - def replaceAllIn(target: java.lang.CharSequence, replacer: Match => String): String = { + def replaceAllIn(target: CharSequence, replacer: Match => String): String = { val it = new Regex.MatchIterator(target, this, groupNames).replacementData it foreach (md => it replace replacer(md)) it.replaced @@ -343,7 +371,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable { * @param replacer The function which optionally maps a match to another string. * @return The target string after replacements. */ - def replaceSomeIn(target: java.lang.CharSequence, replacer: Match => Option[String]): String = { + def replaceSomeIn(target: CharSequence, replacer: Match => Option[String]): String = { val it = new Regex.MatchIterator(target, this, groupNames).replacementData for (matchdata <- it ; replacement <- replacer(matchdata)) it replace replacement @@ -359,7 +387,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable { * @param replacement The string that will replace the match * @return The resulting string */ - def replaceFirstIn(target: java.lang.CharSequence, replacement: String): String = { + def replaceFirstIn(target: CharSequence, replacement: String): String = { val m = pattern.matcher(target) m.replaceFirst(replacement) } @@ -370,7 +398,7 @@ class Regex(regex: String, groupNames: String*) extends Serializable { * @return The array of strings computed by splitting the * input around matches of this regexp */ - def split(toSplit: java.lang.CharSequence): Array[String] = + def split(toSplit: CharSequence): Array[String] = pattern.split(toSplit) /** Create a new Regex with the same pattern, but no requirement that @@ -390,9 +418,11 @@ class Regex(regex: String, groupNames: String*) extends Serializable { * * @return The new unanchored regex */ - def unanchored: UnanchoredRegex = new Regex(regex, groupNames: _*) with UnanchoredRegex { override def anchored = outer } + def unanchored: UnanchoredRegex = new Regex(pattern, groupNames: _*) with UnanchoredRegex { override def anchored = outer } def anchored: Regex = this + def regex: String = pattern.pattern + /** The string defining the regular expression */ override def toString = regex } @@ -421,7 +451,7 @@ object Regex { trait MatchData { /** The source from where the match originated */ - val source: java.lang.CharSequence + val source: CharSequence /** The names of the groups, or some empty sequence if one defined */ val groupNames: Seq[String] @@ -459,25 +489,25 @@ object Regex { /** The char sequence before first character of match, * or `null` if nothing was matched */ - def before: java.lang.CharSequence = + def before: CharSequence = if (start >= 0) source.subSequence(0, start) else null /** The char sequence before first character of match in group `i`, * or `null` if nothing was matched for that group */ - def before(i: Int): java.lang.CharSequence = + def before(i: Int): CharSequence = if (start(i) >= 0) source.subSequence(0, start(i)) else null /** Returns char sequence after last character of match, * or `null` if nothing was matched */ - def after: java.lang.CharSequence = + def after: CharSequence = if (end >= 0) source.subSequence(end, source.length) else null /** The char sequence after last character of match in group `i`, * or `null` if nothing was matched for that group */ - def after(i: Int): java.lang.CharSequence = + def after(i: Int): CharSequence = if (end(i) >= 0) source.subSequence(end(i), source.length) else null @@ -501,8 +531,8 @@ object Regex { /** Provides information about a succesful match. */ - class Match(val source: java.lang.CharSequence, - matcher: Matcher, + class Match(val source: CharSequence, + private[matching] val matcher: Matcher, val groupNames: Seq[String]) extends MatchData { /** The index of the first matched character */ @@ -563,7 +593,7 @@ object Regex { /** A class to step through a sequence of regex matches */ - class MatchIterator(val source: java.lang.CharSequence, val regex: Regex, val groupNames: Seq[String]) + class MatchIterator(val source: CharSequence, val regex: Regex, val groupNames: Seq[String]) extends AbstractIterator[String] with Iterator[String] with MatchData { self => protected[Regex] val matcher = regex.pattern.matcher(source) -- cgit v1.2.3 From 29a59700b4cf1ade91abb6020ba4814be5ef88e7 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 29 Sep 2012 14:20:21 -0700 Subject: Added utility function shortClass. Pretty sick of names like scala> typeOf[List[Int]].getClass.getName res0: String = scala.reflect.internal.Types$TypeRef$$anon$1 I wrote this so I can see what the class of some arbitrary thing is in a way which my little brain can understand. For the example above we get scala> shortClassOfInstance(typeOf[List[Int]]) res0: String = ArgsTypeRef with AliasTypeRef Let's pimp a "shortClassName" onto AnyRef and be happy. --- .../tools/nsc/interpreter/JLineCompletion.scala | 13 ++------- src/reflect/scala/reflect/internal/Symbols.scala | 4 +-- .../scala/reflect/internal/util/StringOps.scala | 8 +++++ .../scala/reflect/internal/util/package.scala | 34 ++++++++++++++++++++++ test/files/run/shortClass.check | 10 +++++++ test/files/run/shortClass.scala | 24 +++++++++++++++ 6 files changed, 80 insertions(+), 13 deletions(-) create mode 100644 src/reflect/scala/reflect/internal/util/package.scala create mode 100644 test/files/run/shortClass.check create mode 100644 test/files/run/shortClass.scala (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala b/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala index b390ad5417..9a4be27c76 100644 --- a/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala +++ b/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala @@ -10,6 +10,7 @@ import scala.tools.jline._ import scala.tools.jline.console.completer._ import Completion._ import scala.collection.mutable.ListBuffer +import scala.reflect.internal.util.StringOps.longestCommonPrefix // REPL completor - queries supplied interpreter for valid // completions based on current contents of buffer. @@ -301,16 +302,6 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput def isConsecutiveTabs(buf: String, cursor: Int) = cursor == lastCursor && buf == lastBuf - // Longest common prefix - def commonPrefix(xs: List[String]): String = { - if (xs.isEmpty || xs.contains("")) "" - else xs.head.head match { - case ch => - if (xs.tail forall (_.head == ch)) "" + ch + commonPrefix(xs map (_.tail)) - else "" - } - } - // This is jline's entry point for completion. override def complete(buf: String, cursor: Int): Candidates = { verbosity = if (isConsecutiveTabs(buf, cursor)) verbosity + 1 else 0 @@ -324,7 +315,7 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput val newCursor = if (winners contains "") p.cursor else { - val advance = commonPrefix(winners) + val advance = longestCommonPrefix(winners) lastCursor = p.position + advance.length lastBuf = (buf take p.position) + advance repldbg("tryCompletion(%s, _) lastBuf = %s, lastCursor = %s, p.position = %s".format( diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 3adcd86c73..c0d15450e9 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -8,7 +8,7 @@ package internal import scala.collection.{ mutable, immutable } import scala.collection.mutable.ListBuffer -import util.Statistics +import util.{ Statistics, shortClassOfInstance } import Flags._ import scala.annotation.tailrec import scala.reflect.io.AbstractFile @@ -182,7 +182,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => if (isGADTSkolem) " (this is a GADT skolem)" else "" - def shortSymbolClass = getClass.getName.split('.').last.stripPrefix("Symbols$") + def shortSymbolClass = shortClassOfInstance(this) def symbolCreationString: String = ( "%s%25s | %-40s | %s".format( if (settings.uniqid.value) "%06d | ".format(id) else "", diff --git a/src/reflect/scala/reflect/internal/util/StringOps.scala b/src/reflect/scala/reflect/internal/util/StringOps.scala index 281ade8134..e4ad8559e2 100644 --- a/src/reflect/scala/reflect/internal/util/StringOps.scala +++ b/src/reflect/scala/reflect/internal/util/StringOps.scala @@ -34,6 +34,14 @@ trait StringOps { s.substring(0, idx + 1) } } + def longestCommonPrefix(xs: List[String]): String = { + if (xs.isEmpty || xs.contains("")) "" + else xs.head.head match { + case ch => + if (xs.tail forall (_.head == ch)) "" + ch + longestCommonPrefix(xs map (_.tail)) + else "" + } + } def decompose(str: String, sep: Char): List[String] = { def ws(start: Int): List[String] = diff --git a/src/reflect/scala/reflect/internal/util/package.scala b/src/reflect/scala/reflect/internal/util/package.scala new file mode 100644 index 0000000000..83c8bf67ba --- /dev/null +++ b/src/reflect/scala/reflect/internal/util/package.scala @@ -0,0 +1,34 @@ +package scala +package reflect +package internal + +package object util { + import StringOps.longestCommonPrefix + + // Shorten a name like Symbols$FooSymbol to FooSymbol. + private def shortenName(name: String): String = { + if (name == "") return "" + val segments = (name split '$').toList + val last = segments.last + + if (last.length == 0) + segments takeRight 2 mkString "$" + else + last + } + + def shortClassOfInstance(x: AnyRef): String = shortClass(x.getClass) + def shortClass(clazz: Class[_]): String = { + val name: String = (clazz.getName split '.').last + def isModule = name endsWith "$" // object + def isAnon = (name split '$').last forall (_.isDigit) // anonymous class + + if (isModule) + (name split '$' filterNot (_ == "")).last + "$" + else if (isAnon) { + val parents = clazz.getSuperclass :: clazz.getInterfaces.toList + parents map (c => shortClass(c)) mkString " with " + } + else shortenName(name) + } +} diff --git a/test/files/run/shortClass.check b/test/files/run/shortClass.check new file mode 100644 index 0000000000..fbdb725cca --- /dev/null +++ b/test/files/run/shortClass.check @@ -0,0 +1,10 @@ +bippity.bop.Foo +bippity.bop.Foo$Bar +bippity.bop.Foo$Bar$ +Test$$anon$1 +Test$$anon$2 +Foo +Bar +Bar$ +Foo with DingDongBippy +Bar with DingDongBippy diff --git a/test/files/run/shortClass.scala b/test/files/run/shortClass.scala new file mode 100644 index 0000000000..b7bb016896 --- /dev/null +++ b/test/files/run/shortClass.scala @@ -0,0 +1,24 @@ +import scala.reflect.internal.util._ + +package bippity { + trait DingDongBippy + + package bop { + class Foo { + class Bar + object Bar + } + } +} + +object Test { + import bippity._ + import bop._ + + def main(args: Array[String]): Unit = { + val f = new Foo + val instances = List(f, new f.Bar, f.Bar, new Foo with DingDongBippy, new f.Bar with DingDongBippy) + instances map (_.getClass.getName) foreach println + instances map shortClassOfInstance foreach println + } +} -- cgit v1.2.3 From dee6a347335e9a4b42342664aa50b0cb217c00a9 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Wed, 3 Oct 2012 13:54:30 -0700 Subject: Renamed hasSymbol to hasSymbolField. Suggestion by retronym that the obvious implementation of "hasSymbol" be called "hasSymbol" reminded me we have a method called "hasSymbol" which does not have that implementation, and which has burned us already with subtle bugginess. I think that "hasSymbolField" is self-documenting. --- .../scala/reflect/reify/codegen/GenTrees.scala | 6 +++--- .../scala/reflect/reify/phases/Metalevels.scala | 2 +- .../scala/tools/nsc/ast/TreeBrowsers.scala | 2 +- src/compiler/scala/tools/nsc/ast/TreeGen.scala | 2 +- src/compiler/scala/tools/nsc/ast/Trees.scala | 2 +- .../scala/tools/nsc/symtab/classfile/Pickler.scala | 4 ++-- .../scala/tools/nsc/transform/AddInterfaces.scala | 2 +- src/compiler/scala/tools/nsc/transform/Mixin.scala | 4 ++-- .../scala/tools/nsc/typechecker/Duplicators.scala | 4 ++-- .../scala/tools/nsc/typechecker/Infer.scala | 2 +- .../tools/nsc/typechecker/PatternMatching.scala | 2 +- .../scala/tools/nsc/typechecker/Typers.scala | 22 ++++++++++---------- .../scala/tools/reflect/ToolBoxFactory.scala | 2 +- src/detach/plugin/scala/tools/detach/Detach.scala | 24 +++++++++++----------- src/reflect/scala/reflect/api/Trees.scala | 2 +- src/reflect/scala/reflect/internal/Importers.scala | 6 +++--- src/reflect/scala/reflect/internal/Printers.scala | 6 +++--- src/reflect/scala/reflect/internal/Trees.scala | 9 ++++---- 18 files changed, 52 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala index bdcc7383b0..86ad23cd15 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala @@ -64,7 +64,7 @@ trait GenTrees { // usually we don't reify symbols/types, because they can be re-inferred during subsequent reflective compilation // however, reification of AnnotatedTypes is special. see ``reifyType'' to find out why. - if (reifyTreeSymbols && tree.hasSymbol) { + if (reifyTreeSymbols && tree.hasSymbolField) { if (reifyDebug) println("reifying symbol %s for tree %s".format(tree.symbol, tree)) rtree = mirrorBuildCall(nme.setSymbol, rtree, reify(tree.symbol)) } @@ -86,8 +86,8 @@ trait GenTrees { // see ``Metalevels'' for more info about metalevel breaches // and about how we deal with splices that contain them - val isMetalevelBreach = splicee exists (sub => sub.hasSymbol && sub.symbol != NoSymbol && sub.symbol.metalevel > 0) - val isRuntimeEval = splicee exists (sub => sub.hasSymbol && sub.symbol == ExprSplice) + val isMetalevelBreach = splicee exists (sub => sub.hasSymbolField && sub.symbol != NoSymbol && sub.symbol.metalevel > 0) + val isRuntimeEval = splicee exists (sub => sub.hasSymbolField && sub.symbol == ExprSplice) if (isMetalevelBreach || isRuntimeEval) { // we used to convert dynamic splices into runtime evals transparently, but we no longer do that // why? see comments in ``Metalevels'' diff --git a/src/compiler/scala/reflect/reify/phases/Metalevels.scala b/src/compiler/scala/reflect/reify/phases/Metalevels.scala index fbbd12a42f..4c6ebbb288 100644 --- a/src/compiler/scala/reflect/reify/phases/Metalevels.scala +++ b/src/compiler/scala/reflect/reify/phases/Metalevels.scala @@ -124,7 +124,7 @@ trait Metalevels { withinSplice { super.transform(TreeSplice(ReifiedTree(universe, mirror, symtab1, rtree, tpe, rtpe, concrete))) } case TreeSplice(splicee) => if (reifyDebug) println("entering splice: " + splicee) - val breaches = splicee filter (sub => sub.hasSymbol && sub.symbol != NoSymbol && sub.symbol.metalevel > 0) + val breaches = splicee filter (sub => sub.hasSymbolField && sub.symbol != NoSymbol && sub.symbol.metalevel > 0) if (!insideSplice && breaches.nonEmpty) { // we used to convert dynamic splices into runtime evals transparently, but we no longer do that // why? see comments above diff --git a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala index 267a5dcefd..be7a6295b4 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala @@ -509,7 +509,7 @@ abstract class TreeBrowsers { /** Return a textual representation of this t's symbol */ def symbolText(t: Tree): String = { val prefix = - if (t.hasSymbol) "[has] " + if (t.hasSymbolField) "[has] " else if (t.isDef) "[defines] " else "" diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index 20da5f0087..a74b62bf8d 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -22,7 +22,7 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL { def mkCheckInit(tree: Tree): Tree = { val tpe = - if (tree.tpe != null || !tree.hasSymbol) tree.tpe + if (tree.tpe != null || !tree.hasSymbolField) tree.tpe else tree.symbol.tpe if (!global.phase.erasedTypes && settings.warnSelectNullable.value && diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 3ccc595fb2..f6073cf185 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -341,7 +341,7 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => tree case _ => val dupl = tree.duplicate - if (tree.hasSymbol && (!localOnly || (locals contains tree.symbol)) && !(keepLabels && tree.symbol.isLabel)) + if (tree.hasSymbolField && (!localOnly || (locals contains tree.symbol)) && !(keepLabels && tree.symbol.isLabel)) dupl.symbol = NoSymbol dupl.tpe = null dupl diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala index 5dbd22f23b..182338a0a1 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala @@ -68,7 +68,7 @@ abstract class Pickler extends SubComponent { return } - if (!t.isDef && t.hasSymbol && t.symbol.isTermMacro) { + if (!t.isDef && t.hasSymbolField && t.symbol.isTermMacro) { unit.error(t.pos, t.symbol.typeParams.length match { case 0 => "macro has not been expanded" case 1 => "this type parameter must be specified" @@ -235,7 +235,7 @@ abstract class Pickler extends SubComponent { private def putTree(tree: Tree): Unit = if (putEntry(tree)) { if (tree != EmptyTree) putType(tree.tpe) - if (tree.hasSymbol) + if (tree.hasSymbolField) putSymbol(tree.symbol) tree match { diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala index 3e0e40e525..32c2d63b2a 100644 --- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala +++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala @@ -321,7 +321,7 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure => Block(List(Apply(gen.mkSuperInitCall, Nil)), expr) case Block(stats, expr) => - // needs `hasSymbol` check because `supercall` could be a block (named / default args) + // needs `hasSymbolField` check because `supercall` could be a block (named / default args) val (presuper, supercall :: rest) = stats span (t => t.hasSymbolWhich(_ hasFlag PRESUPER)) treeCopy.Block(tree, presuper ::: (supercall :: mixinConstructorCalls ::: rest), expr) } diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index 27ceb66af4..b54f128961 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -438,7 +438,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { tree match { case Assign(lhs, rhs) => traverse(rhs) // assignments don't count case _ => - if (tree.hasSymbol && tree.symbol != NoSymbol) { + if (tree.hasSymbolField && tree.symbol != NoSymbol) { val sym = tree.symbol if ((sym.hasAccessorFlag || (sym.isTerm && !sym.isMethod)) && sym.isPrivate @@ -804,7 +804,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { */ class TreeSymSubstituterWithCopying(from: List[Symbol], to: List[Symbol]) extends TreeSymSubstituter(from, to) { override def transform(tree: Tree): Tree = - if (tree.hasSymbol && from.contains(tree.symbol)) + if (tree.hasSymbolField && from.contains(tree.symbol)) super.transform(tree.duplicate) else super.transform(tree.duplicate) diff --git a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala index 2dd0836322..1bd2bbcd5c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala @@ -233,7 +233,7 @@ abstract class Duplicators extends Analyzer { override def typed(tree: Tree, mode: Int, pt: Type): Tree = { debuglog("typing " + tree + ": " + tree.tpe + ", " + tree.getClass) val origtreesym = tree.symbol - if (tree.hasSymbol && tree.symbol != NoSymbol + if (tree.hasSymbolField && tree.symbol != NoSymbol && !tree.symbol.isLabel // labels cannot be retyped by the type checker as LabelDef has no ValDef/return type trees && invalidSyms.isDefinedAt(tree.symbol)) { debuglog("removed symbol " + tree.symbol) @@ -403,7 +403,7 @@ abstract class Duplicators extends Analyzer { case _ => debuglog("Duplicators default case: " + tree.summaryString) debuglog(" ---> " + tree) - if (tree.hasSymbol && tree.symbol != NoSymbol && (tree.symbol.owner == definitions.AnyClass)) { + if (tree.hasSymbolField && tree.symbol != NoSymbol && (tree.symbol.owner == definitions.AnyClass)) { tree.symbol = NoSymbol // maybe we can find a more specific member in a subclass of Any (see AnyVal members, like ==) } val ntree = castType(tree, pt) diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index d9f0c150ce..472cfed894 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -269,7 +269,7 @@ trait Infer extends Checkable { def errorValue = if (context.reportErrors) context.owner.newErrorValue(name) else stdErrorValue def errorSym = if (tree.isType) errorClass else errorValue - if (tree.hasSymbol) + if (tree.hasSymbolField) tree setSymbol errorSym tree setType ErrorType diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala index 52880609e9..96e1ed9a1c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala @@ -2547,7 +2547,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL } val toString = - if (p.hasSymbol && p.symbol.isStable) p.symbol.name.toString // tp.toString + if (p.hasSymbolField && p.symbol.isStable) p.symbol.name.toString // tp.toString else p.toString //+"#"+ id Const.unique(narrowTp, new ValueConst(narrowTp, checkableType(wideTp), toString)) // must make wide type checkable so that it is comparable to types from TypeConst diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index dc6beaf5c6..12e26a812d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -53,7 +53,7 @@ trait Typers extends Modes with Adaptations with Tags { object UnTyper extends Traverser { override def traverse(tree: Tree) = { if (tree != EmptyTree) tree.tpe = null - if (tree.hasSymbol) tree.symbol = NoSymbol + if (tree.hasSymbolField) tree.symbol = NoSymbol super.traverse(tree) } } @@ -242,7 +242,7 @@ trait Typers extends Modes with Adaptations with Tags { * of its symbol was not volatile? */ protected def isStableExceptVolatile(tree: Tree) = { - tree.hasSymbol && tree.symbol != NoSymbol && tree.tpe.isVolatile && + tree.hasSymbolField && tree.symbol != NoSymbol && tree.tpe.isVolatile && { val savedTpe = tree.symbol.info val savedSTABLE = tree.symbol getFlag STABLE tree.symbol setInfo AnyRefClass.tpe @@ -915,7 +915,7 @@ trait Typers extends Modes with Adaptations with Tags { // but this needs additional investigation, because it crashes t5228, gadts1 and maybe something else // tree setType tree.tpe.normalize tree - } else if (tree.hasSymbol && !tree.symbol.typeParams.isEmpty && !inHKMode(mode) && + } else if (tree.hasSymbolField && !tree.symbol.typeParams.isEmpty && !inHKMode(mode) && !(tree.symbol.isJavaDefined && context.unit.isJava)) { // (7) // @M When not typing a higher-kinded type ((mode & HKmode) == 0) // or raw type (tree.symbol.isJavaDefined && context.unit.isJava), types must be of kind *, @@ -923,7 +923,7 @@ trait Typers extends Modes with Adaptations with Tags { // @M TODO: why do kind-* tree's have symbols, while higher-kinded ones don't? MissingTypeParametersError(tree) } else if ( // (7.1) @M: check kind-arity - // @M: removed check for tree.hasSymbol and replace tree.symbol by tree.tpe.symbol (TypeTree's must also be checked here, and they don't directly have a symbol) + // @M: removed check for tree.hasSymbolField and replace tree.symbol by tree.tpe.symbol (TypeTree's must also be checked here, and they don't directly have a symbol) (inHKMode(mode)) && // @M: don't check tree.tpe.symbol.typeParams. check tree.tpe.typeParams!!! // (e.g., m[Int] --> tree.tpe.symbol.typeParams.length == 1, tree.tpe.typeParams.length == 0!) @@ -1457,7 +1457,7 @@ trait Typers extends Modes with Adaptations with Tags { // Determine // - supertparams: Missing type parameters from supertype // - supertpe: Given supertype, polymorphic in supertparams - val supertparams = if (supertpt.hasSymbol) supertpt.symbol.typeParams else List() + val supertparams = if (supertpt.hasSymbolField) supertpt.symbol.typeParams else List() var supertpe = supertpt.tpe if (!supertparams.isEmpty) supertpe = PolyType(supertparams, appliedType(supertpe, supertparams map (_.tpeHK))) @@ -2896,7 +2896,7 @@ trait Typers extends Modes with Adaptations with Tags { def duplErrorTree(err: AbsTypeError) = { issue(err); duplErrTree } def preSelectOverloaded(fun: Tree): Tree = { - if (fun.hasSymbol && fun.symbol.isOverloaded) { + if (fun.hasSymbolField && fun.symbol.isOverloaded) { // remove alternatives with wrong number of parameters without looking at types. // less expensive than including them in inferMethodAlternatvie (see below). def shapeType(arg: Tree): Type = arg match { @@ -4200,7 +4200,7 @@ trait Typers extends Modes with Adaptations with Tags { val tpt1 = { val tpt0 = typedTypeConstructor(tpt) if (checkStablePrefixClassType(tpt0)) - if (tpt0.hasSymbol && !tpt0.symbol.typeParams.isEmpty) { + if (tpt0.hasSymbolField && !tpt0.symbol.typeParams.isEmpty) { context.undetparams = cloneSymbols(tpt0.symbol.typeParams) notifyUndetparamsAdded(context.undetparams) TypeTree().setOriginal(tpt0) @@ -4412,12 +4412,12 @@ trait Typers extends Modes with Adaptations with Tags { else doTypedApply(tree, fun2, args, mode, pt) /* - if (fun2.hasSymbol && fun2.symbol.isConstructor && (mode & EXPRmode) != 0) { + if (fun2.hasSymbolField && fun2.symbol.isConstructor && (mode & EXPRmode) != 0) { res.tpe = res.tpe.notNull } */ // TODO: In theory we should be able to call: - //if (fun2.hasSymbol && fun2.symbol.name == nme.apply && fun2.symbol.owner == ArrayClass) { + //if (fun2.hasSymbolField && fun2.symbol.name == nme.apply && fun2.symbol.owner == ArrayClass) { // But this causes cyclic reference for Array class in Cleanup. It is easy to overcome this // by calling ArrayClass.info here (or some other place before specialize). if (fun2.symbol == Array_apply && !res.isErrorTyped) { @@ -5023,7 +5023,7 @@ trait Typers extends Modes with Adaptations with Tags { val tpt1 = typed1(tpt, mode | FUNmode | TAPPmode, WildcardType) if (tpt1.isErrorTyped) { tpt1 - } else if (!tpt1.hasSymbol) { + } else if (!tpt1.hasSymbolField) { AppliedTypeNoParametersError(tree, tpt1.tpe) } else { val tparams = tpt1.symbol.typeParams @@ -5395,7 +5395,7 @@ trait Typers extends Modes with Adaptations with Tags { if (context.retyping && (tree.tpe ne null) && (tree.tpe.isErroneous || !(tree.tpe <:< pt))) { tree.tpe = null - if (tree.hasSymbol) tree.symbol = NoSymbol + if (tree.hasSymbolField) tree.symbol = NoSymbol } alreadyTyped = tree.tpe ne null diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index 95135b84e0..bc8ded62d8 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -102,7 +102,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => }) var expr = new Transformer { override def transform(tree: Tree): Tree = - if (tree.hasSymbol && tree.symbol.isFreeTerm) { + if (tree.hasSymbolField && tree.symbol.isFreeTerm) { tree match { case Ident(_) => val freeTermRef = Ident(freeTermNames(tree.symbol.asFreeTerm)) diff --git a/src/detach/plugin/scala/tools/detach/Detach.scala b/src/detach/plugin/scala/tools/detach/Detach.scala index 376a56beed..d56a7f0fbe 100644 --- a/src/detach/plugin/scala/tools/detach/Detach.scala +++ b/src/detach/plugin/scala/tools/detach/Detach.scala @@ -206,7 +206,7 @@ abstract class Detach extends PluginComponent symSet(capturedObjects, owner) += qsym case Select(qual, name) - if (qual.hasSymbol && + if (qual.hasSymbolField && (sym.owner != owner) && !(sym.ownerChain contains ScalaPackageClass) && !(sym.owner hasFlag JAVA)) => @@ -284,7 +284,7 @@ abstract class Detach extends PluginComponent def isOuter(sym: Symbol): Boolean = sym.isOuterAccessor || sym.name.endsWith(nme.OUTER/*, nme.OUTER.length*/) - if (tree.hasSymbol && isOuter(tree.symbol)) subst(from, to) + if (tree.hasSymbolField && isOuter(tree.symbol)) subst(from, to) super.traverse(tree) } } @@ -293,7 +293,7 @@ abstract class Detach extends PluginComponent private class TreeTypeRefSubstituter(clazz: Symbol) extends Traverser { override def traverse(tree: Tree) { val sym = tree.symbol - if (tree.hasSymbol && isRefClass(sym.tpe) && + if (tree.hasSymbolField && isRefClass(sym.tpe) && (sym.owner.enclClass == clazz) && (sym.isValueParameter || sym.hasFlag(PARAMACCESSOR))) { sym setInfo mkRemoteRefClass(sym.tpe) @@ -329,7 +329,7 @@ abstract class Detach extends PluginComponent } val map = new mutable.HashMap[Symbol, Symbol] override def traverse(tree: Tree) { - if (tree.hasSymbol && tree.symbol != NoSymbol) { + if (tree.hasSymbolField && tree.symbol != NoSymbol) { val sym = tree.symbol if (sym.owner == from) { val sym1 = map get sym match { @@ -369,7 +369,7 @@ abstract class Detach extends PluginComponent def removeAccessors(tree: Tree): Tree = tree match { case Apply(fun, _) => removeAccessors(fun) - case Select(qual, _) if tree.hasSymbol && tree.symbol.isOuterAccessor => + case Select(qual, _) if tree.hasSymbolField && tree.symbol.isOuterAccessor => removeAccessors(qual) case _ => tree @@ -382,7 +382,7 @@ abstract class Detach extends PluginComponent // transforms field assignment $outer.i$1.elem=.. // into setter $outer.i$1_=(..) case Assign(lhs @ Select(qual1 @ Select(qual, name), name1), rhs) - if qual1.hasSymbol && !qual1.symbol.isPrivateLocal && + if qual1.hasSymbolField && !qual1.symbol.isPrivateLocal && isRemoteRefClass(qual1.tpe) => if (DEBUG) println("\nTreeAccessorSubstituter: Assign1\n\tqual1="+qual1+", sel.tpe="+lhs.tpe+ @@ -398,7 +398,7 @@ abstract class Detach extends PluginComponent // transforms local assignment this.x$1.elem=.. // into setter method this.x$1_=(..) case Assign(lhs @ Select(qual, name), rhs) - if qual.hasSymbol && qual.symbol.isPrivateLocal && + if qual.hasSymbolField && qual.symbol.isPrivateLocal && isRemoteRefClass(qual.tpe) => if (DEBUG) println("\nTreeAccessorSubstituter: Assign2"+ @@ -412,7 +412,7 @@ abstract class Detach extends PluginComponent Apply(fun, List(super.transform(rhs))) setType lhs.tpe case Assign(Select(qual, name), rhs) - if qual.hasSymbol && (objs contains qual.symbol) => + if qual.hasSymbolField && (objs contains qual.symbol) => val sym = qual.symbol val proxy = proxySyms(objs indexOf sym) if (DEBUG) @@ -461,7 +461,7 @@ abstract class Detach extends PluginComponent // transforms field $outer.name$1 into getter method $outer.name$1() case Select(qual @ Select(_, name1), name) - if qual.hasSymbol && name1.endsWith(nme.OUTER/*, nme.OUTER.length*/) && + if qual.hasSymbolField && name1.endsWith(nme.OUTER/*, nme.OUTER.length*/) && !tree.symbol.isMethod => if (DEBUG) println("\nTreeAccessorSubstituter: Select0\n\tqual="+qual+ @@ -500,7 +500,7 @@ abstract class Detach extends PluginComponent // transforms field access $outer.i$1.elem // into invocation of getter method $outer.i$1() case Select(qual @ Select(qual1, name1), name) - if qual.hasSymbol && !qual.symbol.isPrivateLocal && + if qual.hasSymbolField && !qual.symbol.isPrivateLocal && isRemoteRefClass(qual.tpe) => if (DEBUG) println("\nTreeAccessorSubstituter: Select2\n\tqual="+qual+ @@ -513,7 +513,7 @@ abstract class Detach extends PluginComponent // transforms local access this.i$1.elem // into invocation of getter method this.i$1() case Select(qual, name) - if qual.hasSymbol && qual.symbol.isPrivateLocal && + if qual.hasSymbolField && qual.symbol.isPrivateLocal && isRemoteRefClass(qual.tpe) => if (DEBUG) println("\nTreeAccessorSubstituter: Select3\n\tqual="+qual+ @@ -523,7 +523,7 @@ abstract class Detach extends PluginComponent Apply(fun, List()) setType tree.tpe case Select(qual, name) - if qual.hasSymbol && (objs contains qual.symbol) => + if qual.hasSymbolField && (objs contains qual.symbol) => if (DEBUG) println("\nTreeAccessorSubstituter: Select4\n\tqual="+qual+ ", qual.tpe="+qual.tpe+", name="+name)//debug diff --git a/src/reflect/scala/reflect/api/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala index 1f15ee6070..bbd5d00be3 100644 --- a/src/reflect/scala/reflect/api/Trees.scala +++ b/src/reflect/scala/reflect/api/Trees.scala @@ -100,7 +100,7 @@ trait Trees { self: Universe => def symbol: Symbol /** ... */ - def hasSymbol: Boolean + def hasSymbolField: Boolean /** Provides an alternate if tree is empty * @param alt The alternate tree diff --git a/src/reflect/scala/reflect/internal/Importers.scala b/src/reflect/scala/reflect/internal/Importers.scala index 43902c1930..ea8d6078ff 100644 --- a/src/reflect/scala/reflect/internal/Importers.scala +++ b/src/reflect/scala/reflect/internal/Importers.scala @@ -427,17 +427,17 @@ trait Importers extends api.Importers { self: SymbolTable => } addFixup({ if (mytree != null) { - val mysym = if (tree.hasSymbol) importSymbol(tree.symbol) else NoSymbol + val mysym = if (tree.hasSymbolField) importSymbol(tree.symbol) else NoSymbol val mytpe = importType(tree.tpe) mytree match { case mytt: TypeTree => val tt = tree.asInstanceOf[from.TypeTree] - if (mytree.hasSymbol) mytt.symbol = mysym + if (mytree.hasSymbolField) mytt.symbol = mysym if (tt.wasEmpty) mytt.defineType(mytpe) else mytt.setType(mytpe) if (tt.original != null) mytt.setOriginal(importTree(tt.original)) case _ => - if (mytree.hasSymbol) mytree.symbol = importSymbol(tree.symbol) + if (mytree.hasSymbolField) mytree.symbol = importSymbol(tree.symbol) mytree.tpe = importType(tree.tpe) } } diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala index fb165ab50f..b4f03cfdd1 100644 --- a/src/reflect/scala/reflect/internal/Printers.scala +++ b/src/reflect/scala/reflect/internal/Printers.scala @@ -546,8 +546,8 @@ trait Printers extends api.Printers { self: SymbolTable => case _ => print(value.toString) } case tree: Tree => - val hasSymbol = tree.hasSymbol && tree.symbol != NoSymbol - val isError = hasSymbol && tree.symbol.name.toString == nme.ERROR.toString + val hasSymbolField = tree.hasSymbolField && tree.symbol != NoSymbol + val isError = hasSymbolField && tree.symbol.name.toString == nme.ERROR.toString printProduct( tree, preamble = _ => { @@ -560,7 +560,7 @@ trait Printers extends api.Printers { self: SymbolTable => if (isError) print("<") print(name) if (isError) print(": error>") - } else if (hasSymbol) { + } else if (hasSymbolField) { tree match { case _: Ident | _: Select | _: SelectFromTypeTree => print(tree.symbol) case _ => print(tree.symbol.name) diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index 0f133c2306..d74a78ebda 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -31,7 +31,8 @@ trait Trees extends api.Trees { self: SymbolTable => def symbol: Symbol = null //!!!OPT!!! symbol is about 3% of hot compile times -- megamorphic dispatch? def symbol_=(sym: Symbol) { throw new UnsupportedOperationException("symbol_= inapplicable for " + this) } def setSymbol(sym: Symbol): this.type = { symbol = sym; this } - def hasSymbol = false + def hasSymbolField = false + @deprecated("Use hasSymbolField", "2.11.0") def hasSymbol = hasSymbolField def isDef = false @@ -62,7 +63,7 @@ trait Trees extends api.Trees { self: SymbolTable => private[scala] def copyAttrs(tree: Tree): this.type = { rawatt = tree.rawatt tpe = tree.tpe - if (hasSymbol) symbol = tree.symbol + if (hasSymbolField) symbol = tree.symbol this } @@ -210,7 +211,7 @@ trait Trees extends api.Trees { self: SymbolTable => trait TypTree extends Tree with TypTreeApi abstract class SymTree extends Tree with SymTreeContextApi { - override def hasSymbol = true + override def hasSymbolField = true override var symbol: Symbol = NoSymbol } @@ -1412,7 +1413,7 @@ trait Trees extends api.Trees { self: SymbolTable => } if (tree.tpe ne null) tree.tpe = symSubst(tree.tpe) - if (tree.hasSymbol) { + if (tree.hasSymbolField) { subst(from, to) tree match { case Ident(name0) if tree.symbol != NoSymbol => -- cgit v1.2.3 From 120e14fadf30b4c39f953832108d19b736dc6f2d Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Tue, 2 Oct 2012 11:21:16 -0700 Subject: Fix for rangepos crasher. wrapClassTagUnapply was generating an unpositioned tree which would crash under -Yrangepos. See SI-6338. --- src/compiler/scala/tools/nsc/typechecker/Typers.scala | 5 +++-- test/files/neg/t3015.check | 5 +---- test/files/pos/classtag-pos.flags | 1 + test/files/pos/classtag-pos.scala | 5 +++++ 4 files changed, 10 insertions(+), 6 deletions(-) create mode 100644 test/files/pos/classtag-pos.flags create mode 100644 test/files/pos/classtag-pos.scala (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 12e26a812d..cf9a07a7e4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3298,12 +3298,13 @@ trait Typers extends Modes with Adaptations with Tags { // println(util.Position.formatMessage(uncheckedPattern.pos, "made unchecked type test into a checked one", true)) val args = List(uncheckedPattern) + val app = atPos(uncheckedPattern.pos)(Apply(classTagExtractor, args)) // must call doTypedUnapply directly, as otherwise we get undesirable rewrites // and re-typechecks of the target of the unapply call in PATTERNmode, // this breaks down when the classTagExtractor (which defineds the unapply member) is not a simple reference to an object, // but an arbitrary tree as is the case here - doTypedUnapply(Apply(classTagExtractor, args), classTagExtractor, classTagExtractor, args, PATTERNmode, pt) - } + doTypedUnapply(app, classTagExtractor, classTagExtractor, args, PATTERNmode, pt) + } // if there's a ClassTag that allows us to turn the unchecked type test for `pt` into a checked type test // return the corresponding extractor (an instance of ClassTag[`pt`]) diff --git a/test/files/neg/t3015.check b/test/files/neg/t3015.check index 4a03c940f4..6948392bb0 100644 --- a/test/files/neg/t3015.check +++ b/test/files/neg/t3015.check @@ -3,7 +3,4 @@ t3015.scala:7: error: scrutinee is incompatible with pattern type; required: String val b(foo) = "foo" ^ -error: type mismatch; - found : _$1 - required: String -two errors found +one error found diff --git a/test/files/pos/classtag-pos.flags b/test/files/pos/classtag-pos.flags new file mode 100644 index 0000000000..281f0a10cd --- /dev/null +++ b/test/files/pos/classtag-pos.flags @@ -0,0 +1 @@ +-Yrangepos diff --git a/test/files/pos/classtag-pos.scala b/test/files/pos/classtag-pos.scala new file mode 100644 index 0000000000..768d2e27f4 --- /dev/null +++ b/test/files/pos/classtag-pos.scala @@ -0,0 +1,5 @@ +import scala.reflect.runtime.universe._ + +class A { + def f[T: TypeTag] = typeOf[T] match { case TypeRef(_, _, args) => args } +} -- cgit v1.2.3 From 1f99df2c66cb1933dd4db74aa872497a4e26975b Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Tue, 2 Oct 2012 11:24:24 -0700 Subject: Eliminated pattern matcher warning. Implicit extractor must be available to pattern match on abstract type. Requires prior commit not to crash under -Yrangepos. --- src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala b/src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala index fe1c4c0ca8..0bf4999fd6 100644 --- a/src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala +++ b/src/compiler/scala/tools/nsc/interpreter/TypeStrings.scala @@ -212,6 +212,7 @@ trait TypeStrings { } private def tparamString[T: ru.TypeTag] : String = { + import ru._ def typeArguments: List[ru.Type] = ru.typeOf[T] match { case ru.TypeRef(_, _, args) => args; case _ => Nil } // [Eugene to Paul] need to use not the `rootMirror`, but a mirror with the REPL's classloader // how do I get to it? acquiring context classloader seems unreliable because of multithreading @@ -256,4 +257,4 @@ trait TypeStrings { ) } -object TypeStrings extends TypeStrings { } \ No newline at end of file +object TypeStrings extends TypeStrings { } -- cgit v1.2.3 From d7354838948be58b8045e1218a9c757d9b90df76 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Tue, 2 Oct 2012 10:37:13 -0700 Subject: Fix for spurious warning. Eliminates spurious "catch block may intercept non-local return" seen in recent builds of master. Unified some catch logic in TreeInfo, and removed some which never worked. --- .../scala/tools/nsc/transform/UnCurry.scala | 19 +++++++-------- .../scala/tools/nsc/typechecker/Typers.scala | 14 +++++------ src/reflect/scala/reflect/internal/TreeInfo.scala | 28 +++++++++++++++------- test/files/neg/catch-all.check | 9 ++++--- test/files/neg/nonlocal-warning.check | 3 ++- test/files/neg/nonlocal-warning.scala | 11 +++++++++ 6 files changed, 53 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index f68cbfc141..ea93ad1bd4 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -205,11 +205,8 @@ abstract class UnCurry extends InfoTransform val keyDef = ValDef(key, New(ObjectClass.tpe)) val tryCatch = Try(body, pat -> rhs) - body foreach { - case Try(t, catches, _) if catches exists treeInfo.catchesThrowable => - unit.warning(body.pos, "catch block may intercept non-local return from " + meth) - case _ => - } + for (Try(t, catches, _) <- body ; cdef <- catches ; if treeInfo catchesThrowable cdef) + unit.warning(body.pos, "catch block may intercept non-local return from " + meth) Block(List(keyDef), tryCatch) } @@ -691,16 +688,16 @@ abstract class UnCurry extends InfoTransform else tree } - + def isThrowable(pat: Tree): Boolean = pat match { - case Typed(Ident(nme.WILDCARD), tpt) => + case Typed(Ident(nme.WILDCARD), tpt) => tpt.tpe =:= ThrowableClass.tpe - case Bind(_, pat) => + case Bind(_, pat) => isThrowable(pat) case _ => false } - + def isDefaultCatch(cdef: CaseDef) = isThrowable(cdef.pat) && cdef.guard.isEmpty def postTransformTry(tree: Try) = { @@ -764,10 +761,10 @@ abstract class UnCurry extends InfoTransform case tree: Try => postTransformTry(tree) - + case Apply(Apply(fn, args), args1) => treeCopy.Apply(tree, fn, args ::: args1) - + case Ident(name) => assert(name != tpnme.WILDCARD_STAR, tree) applyUnary() diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index cf9a07a7e4..9c6f6a0f99 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -5133,14 +5133,12 @@ trait Typers extends Modes with Adaptations with Tags { var block1 = typed(tree.block, pt) var catches1 = typedCases(tree.catches, ThrowableClass.tpe, pt) - for (cdef <- catches1 if cdef.guard.isEmpty) { - def warn(name: Name) = context.warning(cdef.pat.pos, s"This catches all Throwables. If this is really intended, use `case ${name.decoded} : Throwable` to clear this warning.") - def unbound(t: Tree) = t.symbol == null || t.symbol == NoSymbol - cdef.pat match { - case Bind(name, i @ Ident(_)) if unbound(i) => warn(name) - case i @ Ident(name) if unbound(i) => warn(name) - case _ => - } + for (cdef <- catches1; if treeInfo catchesThrowable cdef) { + val name = (treeInfo assignedNameOfPattern cdef).decoded + context.warning(cdef.pat.pos, + s"""|This catches all Throwables, which often has undesirable consequences. + |If intentional, use `case $name : Throwable` to clear this warning.""".stripMargin + ) } val finalizer1 = diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index db062d138f..d4a22886dd 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -397,19 +397,31 @@ abstract class TreeInfo { case _ => false } - /** Does this CaseDef catch Throwable? */ - def catchesThrowable(cdef: CaseDef) = catchesAllOf(cdef, ThrowableClass.tpe) + private def hasNoSymbol(t: Tree) = t.symbol == null || t.symbol == NoSymbol - /** Does this CaseDef catch everything of a certain Type? */ - def catchesAllOf(cdef: CaseDef, threshold: Type) = { - def unbound(t: Tree) = t.symbol == null || t.symbol == NoSymbol + /** If this CaseDef assigns a name to its top-level pattern, + * in the form 'expr @ pattern' or 'expr: pattern', returns + * the name. Otherwise, nme.NO_NAME. + * + * Note: in the case of Constant patterns such as 'case x @ "" =>', + * the pattern matcher eliminates the binding and inlines the constant, + * so as far as this method is likely to be able to determine, + * the name is NO_NAME. + */ + def assignedNameOfPattern(cdef: CaseDef): Name = cdef.pat match { + case Bind(name, _) => name + case Ident(name) => name + case _ => nme.NO_NAME + } + + /** Does this CaseDef catch Throwable? */ + def catchesThrowable(cdef: CaseDef) = ( cdef.guard.isEmpty && (unbind(cdef.pat) match { case Ident(nme.WILDCARD) => true - case i@Ident(name) => unbound(i) - case Typed(_, tpt) => (tpt.tpe != null) && (threshold <:< tpt.tpe) + case i@Ident(name) => hasNoSymbol(i) case _ => false }) - } + ) /** Is this pattern node a catch-all or type-test pattern? */ def isCatchCase(cdef: CaseDef) = cdef match { diff --git a/test/files/neg/catch-all.check b/test/files/neg/catch-all.check index aaf51480c3..2d58dd99a8 100644 --- a/test/files/neg/catch-all.check +++ b/test/files/neg/catch-all.check @@ -1,10 +1,13 @@ -catch-all.scala:2: warning: This catches all Throwables. If this is really intended, use `case _ : Throwable` to clear this warning. +catch-all.scala:2: warning: This catches all Throwables, which often has undesirable consequences. +If intentional, use `case _ : Throwable` to clear this warning. try { "warn" } catch { case _ => } ^ -catch-all.scala:4: warning: This catches all Throwables. If this is really intended, use `case x : Throwable` to clear this warning. +catch-all.scala:4: warning: This catches all Throwables, which often has undesirable consequences. +If intentional, use `case x : Throwable` to clear this warning. try { "warn" } catch { case x => } ^ -catch-all.scala:6: warning: This catches all Throwables. If this is really intended, use `case x : Throwable` to clear this warning. +catch-all.scala:6: warning: This catches all Throwables, which often has undesirable consequences. +If intentional, use `case x : Throwable` to clear this warning. try { "warn" } catch { case _: RuntimeException => ; case x => } ^ error: No warnings can be incurred under -Xfatal-warnings. diff --git a/test/files/neg/nonlocal-warning.check b/test/files/neg/nonlocal-warning.check index 5202df655a..67b3b10095 100644 --- a/test/files/neg/nonlocal-warning.check +++ b/test/files/neg/nonlocal-warning.check @@ -1,4 +1,5 @@ -nonlocal-warning.scala:4: warning: This catches all Throwables. If this is really intended, use `case x : Throwable` to clear this warning. +nonlocal-warning.scala:4: warning: This catches all Throwables, which often has undesirable consequences. +If intentional, use `case x : Throwable` to clear this warning. catch { case x => 11 } ^ nonlocal-warning.scala:2: warning: catch block may intercept non-local return from method foo diff --git a/test/files/neg/nonlocal-warning.scala b/test/files/neg/nonlocal-warning.scala index cc98bd631a..f908a86302 100644 --- a/test/files/neg/nonlocal-warning.scala +++ b/test/files/neg/nonlocal-warning.scala @@ -4,4 +4,15 @@ class Foo { catch { case x => 11 } 22 } + + val pf: PartialFunction[Throwable, Unit] = { + case x if false => () + } + + def bar(l: List[Int]): Int = { + try l foreach { _ => return 5 } + catch pf + finally println() + 22 + } } -- cgit v1.2.3