diff options
author | Martin Odersky <odersky@gmail.com> | 2009-05-27 16:19:05 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2009-05-27 16:19:05 +0000 |
commit | 2039b7fec7b902e3cef0a9c31a94ea96c2e469c8 (patch) | |
tree | cfa00f45f4f0fe0a502aab23e50088783851fa1f /src | |
parent | b22342e78a3134d186f82dac5e1c7be01ece7c17 (diff) | |
download | scala-2039b7fec7b902e3cef0a9c31a94ea96c2e469c8.tar.gz scala-2039b7fec7b902e3cef0a9c31a94ea96c2e469c8.tar.bz2 scala-2039b7fec7b902e3cef0a9c31a94ea96c2e469c8.zip |
Fixed problem that spurious caused exhaustivene...
Fixed problem that spurious caused exhaustiveness warning for RefChecks.
Enriched positions and worked on the interactive compiler.
Diffstat (limited to 'src')
11 files changed, 145 insertions, 45 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala index 57e60f9fba..4292cb24a0 100644 --- a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala @@ -341,8 +341,6 @@ abstract class NodePrinters { } printcln(")") } else printcln(p.productPrefix) - case _ => - printcln("***" + tree.getClass) } } } diff --git a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala index 4deccddde6..9e9b801d25 100644 --- a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala @@ -389,7 +389,7 @@ abstract class TreePrinters { } def print(tree: Tree) { - if (settings.Xprintpos.value) print("[" + tree.pos + "]") + if (settings.Xprintpos.value) print(tree.pos.show) printRaw( if (tree.isDef && tree.symbol != NoSymbol && tree.symbol.isInitialized) { tree match { diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 5e930bb4fc..12c5c9c46d 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -96,7 +96,7 @@ trait Trees { // @M helper method for asserts that check consistency in kinding //def kindingIrrelevant(tp: Type) = (tp eq null) || phase.name == "erasure" || phase.erasedTypes - abstract class Tree { + abstract class Tree extends Product { { import util.Statistics if (Statistics.enabled) nodeCount += 1 @@ -159,6 +159,10 @@ trait Trees { /** Is there part of this tree which satisfies predicate `p'? */ def exists(p: Tree => Boolean): Boolean = !find(p).isEmpty + /** The direct children of this tree */ + def children(): Iterator[Tree] = + productElements filter (_.isInstanceOf[Tree]) map (_.asInstanceOf[Tree]) + override def toString(): String = { val buffer = new StringWriter() val printer = treePrinters.create(new PrintWriter(buffer)) @@ -190,10 +194,7 @@ trait Trees { i += 1 } } - this match { - case p : Product => g(p) - case _ => - } + g(this) hc } def equalsStructure(that : Tree) = equalsStructure0(that){case (t0,t1) => false} @@ -1788,6 +1789,7 @@ trait Trees { override def end: Int = original.pos.end override def underlying = original.pos.underlying override def focus = original.pos.focus + override def show = "["+underlying.show+"]" } } diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 0aa4907fc6..4254be02d5 100755 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -114,6 +114,7 @@ self => def freshName(pos: Position, prefix: String): Name def o2p(offset: Int): Position def r2p(start: Int, mid: Int, end: Int): Position + def t2p(tree: Tree): Position = SyntheticPosition(tree) //private implicit def p2i(pos: Position) = pos.offset.get /** whether a non-continuable syntax error has been seen */ @@ -370,7 +371,7 @@ self => */ def joinComment(trees: => List[Tree]): List[Tree] = { val buf = in.flushDoc - if ((buf ne null) && buf.length > 0) trees map (t => DocDef(buf, t) setPos t.pos) + if ((buf ne null) && buf.length > 0) trees map (t => DocDef(buf, t) setPos t.pos) // !!! take true comment position else trees } @@ -403,13 +404,13 @@ self => tree match { case Ident(name) => removeAsPlaceholder(name) - ValDef(Modifiers(Flags.PARAM), name, TypeTree(), EmptyTree) + ValDef(Modifiers(Flags.PARAM), name, TypeTree() setPos o2p(tree.pos.end), EmptyTree) case Typed(tree @ Ident(name), tpe) if (tpe.isType) => // get the ident! removeAsPlaceholder(name) ValDef(Modifiers(Flags.PARAM), name, tpe, EmptyTree) case _ => syntaxError(tree.pos, "not a legal formal parameter", false) - ValDef(Modifiers(Flags.PARAM), nme.ERROR, errorTypeTree, EmptyTree) + ValDef(Modifiers(Flags.PARAM), nme.ERROR, errorTypeTree setPos o2p(tree.pos.end), EmptyTree) } } @@ -812,7 +813,7 @@ self => def wildcardType(start: Int) = { val pname = freshName(o2p(start), "_$").toTypeName val t = atPos(start) { Ident(pname) } - val param = atPos(start) { makeSyntheticTypeParam(pname, typeBounds()) } + val param = atPos(t2p(t)) { makeSyntheticTypeParam(pname, typeBounds()) } placeholderTypes = param :: placeholderTypes t } @@ -1130,12 +1131,12 @@ self => path(true, false) case USCORE => val start = in.offset - atPos(in.skipToken()) { - val pname = freshName(o2p(start), "x$") - val param = atPos(start){ makeSyntheticParam(pname) } - placeholderParams = param :: placeholderParams - Ident(pname) - } + val pname = freshName(o2p(start), "x$") + val id = atPos(start) (Ident(pname)) + in.nextToken() + val param = atPos(t2p(id)){ makeSyntheticParam(pname) } + placeholderParams = param :: placeholderParams + id case LPAREN => atPos(in.skipToken()) { val ts = if (in.token == RPAREN) List() else exprs() diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala index 0ad7c1b5aa..44001b4b64 100755 --- a/src/compiler/scala/tools/nsc/interactive/Global.scala +++ b/src/compiler/scala/tools/nsc/interactive/Global.scala @@ -28,8 +28,8 @@ self => /** The currently active typer run */ private var currentTyperRun: TyperRun = _ - /** Is a background compiler currently running? */ - private var compiling = false + /** Is a background compiler run needed? */ + private var outOfDate = false /** Is a reload/ background compiler currently running? */ private var acting = false @@ -84,7 +84,7 @@ self => def pollForWork() { scheduler.pollException() match { case Some(ex: CancelActionReq) => if (acting) throw ex - case Some(ex: FreshRunReq) => if (compiling) throw ex + case Some(ex: FreshRunReq) => if (outOfDate) throw ex case Some(ex: Throwable) => throw ex case _ => } @@ -115,16 +115,13 @@ self => while (true) { scheduler.waitForMoreWork() pollForWork() - var continue = true - while (continue) { + while (outOfDate) { try { - compiling = true backgroundCompile() - continue = false } catch { case ex: FreshRunReq => } finally { - compiling = false + outOfDate = false } } } @@ -190,6 +187,7 @@ self => val unit = new RichCompilationUnit(source) unitOfFile(source.file) = unit currentTyperRun.compileLate(unit) + validatePositions(unit.body) unit.status = JustParsed } moveToFront(sources) @@ -199,7 +197,8 @@ self => result set Right(ex) throw ex } - if (compiling) throw new FreshRunReq + if (outOfDate) throw new FreshRunReq + else outOfDate = true } /** Set sync var `result` to a fully attributed tree located at position `pos` */ @@ -218,6 +217,29 @@ self => // ---------------- Helper classes --------------------------- + + def validatePositions(tree: Tree) { + def check(condition: Boolean, msg: => String) { + if (!condition) { + println("**** bad positions:") + println(msg) + println("================= in =================") + println(tree) + } + } + def validate(tree: Tree, encltree: Tree, lefttree: Tree) { + if (encltree.pos.isSynthetic) check(tree.pos.isSynthetic, "synthetic "+encltree+" contains nonsynthetic" + tree) + check(encltree.pos includes tree.pos, encltree+" does not include "+tree) + if (lefttree != EmptyTree) check(lefttree.pos precedes tree.pos, lefttree+" does not not precede "+tree) + var newleft: Tree = EmptyTree + for (ct <- tree.children) { + validate(ct, tree, newleft) + newleft = ct + } + } + validate(tree, tree, EmptyTree) + } + /** A transformer that replaces tree `from` with tree `to` in a given tree */ class TreeReplacer(from: Tree, to: Tree) extends Transformer { override def transform(t: Tree): Tree = { @@ -262,6 +284,7 @@ self => */ def typedTreeAt(pos: Position): Tree = { val tree = locateTree(pos) +// println("at pos "+pos+" was found: "+tree) if (tree.tpe ne null) tree else { val unit = unitOf(pos) diff --git a/src/compiler/scala/tools/nsc/interactive/REPL.scala b/src/compiler/scala/tools/nsc/interactive/REPL.scala index 58477dd693..e773f9f281 100644 --- a/src/compiler/scala/tools/nsc/interactive/REPL.scala +++ b/src/compiler/scala/tools/nsc/interactive/REPL.scala @@ -9,12 +9,66 @@ import scala.tools.nsc.io._ /** Interface of interactive compiler to a client such as an IDE */ -object REPL extends EvalLoop { +object REPL { - val settings = new Settings() - val comp = new Global(settings, new ConsoleReporter(settings)) + val versionMsg = "Scala compiler " + + Properties.versionString + " -- " + + Properties.copyrightString - def prompt = "> " + val prompt = "> " + + var reporter: ConsoleReporter = _ + + def error(msg: String) { + reporter.error(/*new Position */FakePos("scalac"), + msg + "\n scalac -help gives more information") + } + + def process(args: Array[String]) { + val settings = new Settings(error) + reporter = new ConsoleReporter(settings) + val command = new CompilerCommand(args.toList, settings, error, false) + if (command.settings.version.value) + reporter.info(null, versionMsg, true) + else { + try { + object compiler extends Global(command.settings, reporter) + if (reporter.hasErrors) { + reporter.flush() + return + } + if (command.shouldStopWithInfo) { + reporter.info(null, command.getInfoMessage(compiler), true) + } else { + run(compiler) + } + } catch { + case ex @ FatalError(msg) => + if (true || command.settings.debug.value) // !!! + ex.printStackTrace(); + reporter.error(null, "fatal error: " + msg) + } + } + } + + def main(args: Array[String]) { + process(args) + exit(if (reporter.hasErrors) 1 else 0) + } + + def loop(action: (String) => Unit) { + Console.print(prompt) + try { + val line = Console.readLine + if (line.length() > 0) { + action(line) + } + loop(action) + } + catch { + case _: java.io.EOFException => //nop + } + } /** Commands: * @@ -23,12 +77,10 @@ object REPL extends EvalLoop { * * */ - def run() { + def run(comp: Global) { val reloadResult = new SyncVar[Either[Unit, Throwable]] val typeatResult = new SyncVar[Either[comp.Tree, Throwable]] loop { line => - println("["+line+"]") - println((line split " ").toList) (line split " ").toList match { case "reload" :: args => comp.askReload(args map toSourceFile, reloadResult) @@ -55,8 +107,4 @@ object REPL extends EvalLoop { case Right(exc/*: Throwable ??*/) => exc.printStackTrace; println("ERROR: "+exc) } } - - def main(args: Array[String]) { - run() - } } diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala index ca8ad48224..03783d054c 100644 --- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala +++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala @@ -37,6 +37,9 @@ trait Definitions { lazy val ScalaPackage: Symbol = getModule("scala") lazy val ScalaPackageClass: Symbol = ScalaPackage.tpe.typeSymbol + lazy val ScalaCollectionImmutablePackage: Symbol = getModule("scala.collection.immutable") + lazy val ScalaCollectionImmutablePackageClass: Symbol = ScalaCollectionImmutablePackage.tpe.typeSymbol + var AnyClass: Symbol = _ var AnyValClass: Symbol = _ var AnyRefClass: Symbol = _ @@ -111,6 +114,7 @@ trait Definitions { def Iterable_hasNext = getMember(IterableClass, nme.hasNext) lazy val IteratorClass: Symbol = getClass2("scala.Iterator", "scala.collection.Iterator") lazy val SeqClass: Symbol = getClass2("scala.Seq", "scala.collection.Sequence") + lazy val SeqModule: Symbol = getModule2("scala.Seq", "scala.collection.Sequence") lazy val TraversableClass: Symbol = getClass("scala.collection.Traversable") lazy val RandomAccessSeqMutableClass: Symbol = getMember( getModule2("scala.RandomAccessSeq", "scala.collection.Vector"), nme.Mutable) diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala index bb04630985..f19a8e5138 100644 --- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala +++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala @@ -234,6 +234,7 @@ trait StdNames { val Function = newTermName("Function") val Function1 = newTermName("Function1") val Int = newTermName("Int") + val List = newTermName("List") val Long = newTermName("Long") val Nil = newTermName("Nil") val Object = newTermName("Object") diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 89e2028ded..68ae453793 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -560,10 +560,25 @@ trait Typers { self: Analyzer => /** Make symbol accessible. This means: * If symbol refers to package object, insert `.package` as second to last selector. - * Call checkAccessible, which sets symbol's attributes. + * (exception for some symbols in scala package which are dealiased immediately) + * Call checkAccessible, which sets tree's attributes. + * @return modified tree and new prefix type */ - private def makeAccessible(tree: Tree, sym: Symbol, pre: Type, site: Tree): Tree = + private def makeAccessible(tree: Tree, sym: Symbol, pre: Type, site: Tree): (Tree, Type) = if (isInPackageObject(sym, pre.typeSymbol)) { + if (pre.typeSymbol == ScalaPackageClass && sym.isTerm) { + // short cut some aliases. It seems that without that pattern matching + // fails to notice exhaustiveness and to generate good code when + // List extractors are mixed with :: patterns. See Test5 in lists.scala. + def dealias(sym: Symbol) = + (atPos(tree.pos) { gen.mkAttributedRef(sym) }, sym.owner.thisType) + sym.name match { + case nme.List => return dealias(ListModule) + case nme.Seq => return dealias(SeqModule) + case nme.Nil => return dealias(NilModule) + case _ => + } + } val qual = typedQualifier { tree match { case Ident(_) => Ident(nme.PACKAGEkw) @@ -578,10 +593,9 @@ trait Typers { self: Analyzer => case SelectFromTypeTree(_, name) => SelectFromTypeTree(qual, name) } } - val tree2 = checkAccessible(tree1, sym, qual.tpe, qual) - tree2 + (checkAccessible(tree1, sym, qual.tpe, qual), qual.tpe) } else { - checkAccessible(tree, sym, pre, site) + (checkAccessible(tree, sym, pre, site), pre) } private def isInPackageObject(sym: Symbol, pkg: Symbol) = @@ -2943,7 +2957,8 @@ trait Typers { self: Analyzer => case SelectFromTypeTree(_, _) => copy.SelectFromTypeTree(tree, qual, name) } //if (name.toString == "Elem") println("typedSelect "+qual+":"+qual.tpe+" "+sym+"/"+tree1+":"+tree1.tpe) - val result = stabilize(makeAccessible(tree1, sym, qual.tpe, qual), qual.tpe, mode, pt) + val (tree2, pre2) = makeAccessible(tree1, sym, qual.tpe, qual) + val result = stabilize(tree2, pre2, mode, pt) def isPotentialNullDeference() = { phase.id <= currentRun.typerPhase.id && !sym.isConstructor && @@ -3103,7 +3118,8 @@ trait Typers { self: Analyzer => val tree1 = if (qual == EmptyTree) tree else atPos(tree.pos)(Select(qual, name)) // atPos necessary because qualifier might come from startContext - stabilize(makeAccessible(tree1, defSym, pre, qual), pre, mode, pt) + val (tree2, pre2) = makeAccessible(tree1, defSym, pre, qual) + stabilize(tree2, pre2, mode, pt) } } diff --git a/src/compiler/scala/tools/nsc/util/Position.scala b/src/compiler/scala/tools/nsc/util/Position.scala index bd60035a5a..48343fd948 100644 --- a/src/compiler/scala/tools/nsc/util/Position.scala +++ b/src/compiler/scala/tools/nsc/util/Position.scala @@ -98,6 +98,7 @@ trait Position { }) } + def show: String = "["+toString+"]" } case object NoPosition extends Position @@ -114,6 +115,7 @@ case class OffsetPosition(source0: SourceFile, offset0: Int) extends Position { case that => false } override def hashCode = offset0 * 37 + source0.file.hashCode + override def show = "["+point+"]" } /** new for position ranges */ @@ -125,6 +127,7 @@ extends OffsetPosition(source0, point) { override def endOrElse(d: Int) = end override def focus = OffsetPosition(source0, point) override def toString = "RangePosition("+source0+", "+start+", "+point+", "+end+")" + override def show = "["+start+":"+end+"]" } diff --git a/src/compiler/scala/tools/nsc/util/trace.scala b/src/compiler/scala/tools/nsc/util/trace.scala index a24a18ec45..dc78756ec6 100644 --- a/src/compiler/scala/tools/nsc/util/trace.scala +++ b/src/compiler/scala/tools/nsc/util/trace.scala @@ -5,4 +5,8 @@ object trace { println(msg+value) value } + def withFun[T, U](msg: String)(value: T)(fun: T => U): T = { + println(msg+fun(value)) + value + } } |