From 9094822181c398b945b7f30ac1e2b05da9796f53 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Tue, 5 Mar 2013 10:09:34 -0800 Subject: Enabling commit for interactive/scaladoc modules. This is a non-behaviorally-changing setup commit which re-routes bits of code through avenues which can more easily be influenced by subclasses of Global. --- src/compiler/scala/tools/nsc/Global.scala | 12 ++++-- .../scala/tools/nsc/ast/parser/Parsers.scala | 12 +++--- .../scala/tools/nsc/ast/parser/Scanners.scala | 29 +++++++++------ .../tools/nsc/ast/parser/SyntaxAnalyzer.scala | 4 +- src/compiler/scala/tools/nsc/doc/DocParser.scala | 2 +- .../tools/nsc/interactive/CompilerControl.scala | 2 +- .../tools/nsc/interactive/RangePositions.scala | 1 + .../scala/tools/nsc/javac/JavaScanners.scala | 43 ++++++++-------------- .../scala/tools/nsc/symtab/SymbolLoaders.scala | 34 ++++++++--------- .../scala/tools/nsc/typechecker/Infer.scala | 2 +- .../scala/tools/nsc/typechecker/Namers.scala | 31 +++++++++------- .../scala/tools/nsc/typechecker/Typers.scala | 12 +++--- .../scala/tools/reflect/ToolBoxFactory.scala | 2 +- src/reflect/scala/reflect/internal/Symbols.scala | 22 +++++++---- 14 files changed, 111 insertions(+), 97 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 51fa8f0ab9..bc18b06e2a 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -425,12 +425,14 @@ class Global(var currentSettings: Settings, var reporter: Reporter) val printInfers = settings.Yinferdebug.value // phaseName = "parser" - object syntaxAnalyzer extends { + lazy val syntaxAnalyzer = new { val global: Global.this.type = Global.this val runsAfter = List[String]() val runsRightAfter = None } with SyntaxAnalyzer + import syntaxAnalyzer.{ UnitScanner, UnitParser } + // !!! I think we're overdue for all these phase objects being lazy vals. // There's no way for a Global subclass to provide a custom typer // despite the existence of a "def newTyper(context: Context): Typer" @@ -1120,9 +1122,11 @@ class Global(var currentSettings: Settings, var reporter: Reporter) warning("there were %d %s warning(s); re-run with %s for details".format(warnings.size, what, option.name)) } - def newUnitParser(code: String) = new syntaxAnalyzer.UnitParser(newCompilationUnit(code)) - def newCompilationUnit(code: String) = new CompilationUnit(newSourceFile(code)) - def newSourceFile(code: String) = new BatchSourceFile("", code) + def newCompilationUnit(code: String) = new CompilationUnit(newSourceFile(code)) + def newSourceFile(code: String) = new BatchSourceFile("", code) + def newUnitScanner(unit: CompilationUnit): UnitScanner = new UnitScanner(unit) + def newUnitParser(unit: CompilationUnit): UnitParser = new UnitParser(unit) + def newUnitParser(code: String): UnitParser = newUnitParser(newCompilationUnit(code)) /** A Run is a single execution of the compiler on a sets of units */ diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 08a6adfded..522c45f9fa 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -142,9 +142,9 @@ self => if (source.isSelfContained) () => compilationUnit() else () => scriptBody() - def newScanner = new SourceFileScanner(source) + def newScanner(): Scanner = new SourceFileScanner(source) - val in = newScanner + val in = newScanner() in.init() private val globalFresh = new FreshNameCreator.Default @@ -196,10 +196,9 @@ self => } class UnitParser(val unit: global.CompilationUnit, patches: List[BracePatch]) extends SourceFileParser(unit.source) { + def this(unit: global.CompilationUnit) = this(unit, Nil) - def this(unit: global.CompilationUnit) = this(unit, List()) - - override def newScanner = new UnitScanner(unit, patches) + override def newScanner() = new UnitScanner(unit, patches) override def freshTermName(prefix: String): TermName = unit.freshTermName(prefix) override def freshTypeName(prefix: String): TypeName = unit.freshTypeName(prefix) @@ -219,6 +218,7 @@ self => try body finally smartParsing = saved } + def withPatches(patches: List[BracePatch]): UnitParser = new UnitParser(unit, patches) val syntaxErrors = new ListBuffer[(Int, String)] def showSyntaxErrors() = @@ -244,7 +244,7 @@ self => if (syntaxErrors.isEmpty) firstTry else in.healBraces() match { case Nil => showSyntaxErrors() ; firstTry - case patches => new UnitParser(unit, patches).parse() + case patches => (this withPatches patches).parse() } } } diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index 19cf1b5093..78041fda08 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -9,7 +9,7 @@ import scala.tools.nsc.util.CharArrayReader import scala.reflect.internal.util._ import scala.reflect.internal.Chars._ import Tokens._ -import scala.annotation.switch +import scala.annotation.{ switch, tailrec } import scala.collection.{ mutable, immutable } import mutable.{ ListBuffer, ArrayBuffer } import scala.xml.Utility.{ isNameStart } @@ -1233,7 +1233,7 @@ trait Scanners extends ScannersCommon { /** A scanner over a given compilation unit */ - class UnitScanner(unit: CompilationUnit, patches: List[BracePatch]) extends SourceFileScanner(unit.source) { + class UnitScanner(val unit: CompilationUnit, patches: List[BracePatch]) extends SourceFileScanner(unit.source) { def this(unit: CompilationUnit) = this(unit, List()) override def deprecationWarning(off: Offset, msg: String) = unit.deprecationWarning(unit.position(off), msg) @@ -1382,17 +1382,24 @@ trait Scanners extends ScannersCommon { bpbuf += current } } + def bracePairString(bp: BracePair, indent: Int): String = { + val rangeString = { + import bp._ + val lline = line(loff) + val rline = line(roff) + val tokens = List(lline, lindent, rline, rindent) map (n => if (n < 0) "??" else "" + n) + "%s:%s to %s:%s".format(tokens: _*) + } + val outer = (" " * indent) + rangeString + val inners = bp.nested map (bracePairString(_, indent + 2)) - def printBP(bp: BracePair, indent: Int) { - println(" "*indent+line(bp.loff)+":"+bp.lindent+" to "+line(bp.roff)+":"+bp.rindent) - if (bp.nested.nonEmpty) - for (bp1 <- bp.nested) { - printBP(bp1, indent + 2) - } + if (inners.isEmpty) outer + else inners.mkString(outer + "\n", "\n", "") } -// println("lineStart = "+lineStart)//DEBUG -// println("bracepairs = ") -// for (bp <- bpbuf.toList) printBP(bp, 0) + def bpString = bpbuf.toList map ("\n" + bracePairString(_, 0)) mkString "" + def startString = lineStart.mkString("line starts: [", ", ", "]") + + log(s"\n$startString\n$bpString") bpbuf.toList } diff --git a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala index f1bf590ebf..7cf5a07291 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala @@ -28,8 +28,8 @@ abstract class SyntaxAnalyzer extends SubComponent with Parsers with MarkupParse if (unit.body == EmptyTree) { unit.body = if (unit.isJava) new JavaUnitParser(unit).parse() - else if (reporter.incompleteHandled) new UnitParser(unit).parse() - else new UnitParser(unit).smartParse() + else if (reporter.incompleteHandled) newUnitParser(unit).parse() + else newUnitParser(unit).smartParse() } if (settings.Yrangepos.value && !reporter.hasErrors) diff --git a/src/compiler/scala/tools/nsc/doc/DocParser.scala b/src/compiler/scala/tools/nsc/doc/DocParser.scala index b753e84426..6dc3e5a62b 100644 --- a/src/compiler/scala/tools/nsc/doc/DocParser.scala +++ b/src/compiler/scala/tools/nsc/doc/DocParser.scala @@ -42,7 +42,7 @@ class DocParser(settings: nsc.Settings, reporter: Reporter) extends Global(setti */ def docUnit(code: String) = { val unit = new CompilationUnit(new BatchSourceFile("", code)) - val scanner = new syntaxAnalyzer.UnitParser(unit) + val scanner = newUnitParser(unit) scanner.compilationUnit() } diff --git a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala index 523e0d57b7..f84fa161c0 100644 --- a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala +++ b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala @@ -263,7 +263,7 @@ trait CompilerControl { self: Global => * compiler thread. */ def parseTree(source: SourceFile): Tree = { - new UnitParser(new CompilationUnit(source)).parse() + newUnitParser(new CompilationUnit(source)).parse() } /** Asks for a computation to be done quickly on the presentation compiler thread */ diff --git a/src/compiler/scala/tools/nsc/interactive/RangePositions.scala b/src/compiler/scala/tools/nsc/interactive/RangePositions.scala index 6288400629..c57e1da184 100644 --- a/src/compiler/scala/tools/nsc/interactive/RangePositions.scala +++ b/src/compiler/scala/tools/nsc/interactive/RangePositions.scala @@ -10,4 +10,5 @@ package interactive trait RangePositions extends scala.reflect.internal.Positions with ast.Trees with ast.Positions { self: scala.tools.nsc.Global => + override def useOffsetPositions = false } diff --git a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala index 1d1469f87d..3813736535 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala @@ -10,7 +10,7 @@ import scala.tools.nsc.util.JavaCharArrayReader import scala.reflect.internal.util._ import scala.reflect.internal.Chars._ import JavaTokens._ -import scala.annotation.switch +import scala.annotation.{ switch, tailrec } import scala.language.implicitConversions // Todo merge these better with Scanners @@ -587,33 +587,20 @@ trait JavaScanners extends ast.parser.ScannersCommon { } } - private def skipComment(): Boolean = { - if (in.ch == '/') { - do { - in.next() - } while ((in.ch != CR) && (in.ch != LF) && (in.ch != SU)) - true - } else if (in.ch == '*') { - docBuffer = null - in.next() - val scalaDoc = ("/**", "*/") - if (in.ch == '*' && forScaladoc) - docBuffer = new StringBuilder(scalaDoc._1) - do { - do { - if (in.ch != '*' && in.ch != SU) { - in.next(); putDocChar(in.ch) - } - } while (in.ch != '*' && in.ch != SU) - while (in.ch == '*') { - in.next(); putDocChar(in.ch) - } - } while (in.ch != '/' && in.ch != SU) - if (in.ch == '/') in.next() - else incompleteInputError("unclosed comment") - true - } else { - false + protected def skipComment(): Boolean = { + @tailrec def skipLineComment(): Unit = in.ch match { + case CR | LF | SU => + case _ => in.next; skipLineComment() + } + @tailrec def skipJavaComment(): Unit = in.ch match { + case SU => incompleteInputError("unclosed comment") + case '*' => in.next; if (in.ch == '/') in.next else skipJavaComment() + case _ => in.next; skipJavaComment() + } + in.ch match { + case '/' => in.next ; skipLineComment() ; true + case '*' => in.next ; skipJavaComment() ; true + case _ => false } } diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index 5b5118a94f..ffccc11474 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -30,6 +30,18 @@ abstract class SymbolLoaders { member } + protected def signalError(root: Symbol, ex: Throwable) { + if (settings.debug.value) ex.printStackTrace() + // SI-5593 Scaladoc's current strategy is to visit all packages in search of user code that can be documented + // therefore, it will rummage through the classpath triggering errors whenever it encounters package objects + // that are not in their correct place (see bug for details) + if (!settings.isScaladoc) + globalError(ex.getMessage() match { + case null => "i/o error while loading " + root.name + case msg => "error while loading " + root.name + ", " + msg + }) + } + /** Enter class with given `name` into scope of `root` * and give them `completer` as type. */ @@ -168,18 +180,6 @@ abstract class SymbolLoaders { } override def complete(root: Symbol) { - def signalError(ex: Exception) { - ok = false - if (settings.debug.value) ex.printStackTrace() - val msg = ex.getMessage() - // SI-5593 Scaladoc's current strategy is to visit all packages in search of user code that can be documented - // therefore, it will rummage through the classpath triggering errors whenever it encounters package objects - // that are not in their correct place (see bug for details) - if (!settings.isScaladoc) - globalError( - if (msg eq null) "i/o error while loading " + root.name - else "error while loading " + root.name + ", " + msg) - } try { val start = currentTime val currentphase = phase @@ -189,11 +189,11 @@ abstract class SymbolLoaders { ok = true setSource(root) setSource(root.companionSymbol) // module -> class, class -> module - } catch { - case ex: IOException => - signalError(ex) - case ex: MissingRequirementError => - signalError(ex) + } + catch { + case ex @ (_: IOException | _: MissingRequirementError) => + ok = false + signalError(root, ex) } initRoot(root) if (!root.isPackageClass) initRoot(root.companionSymbol) diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index d4f402b747..9f16f65a6a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -1694,7 +1694,7 @@ trait Infer extends Checkable { } else if (sym.isOverloaded) { val xs = sym.alternatives - val tparams = new AsSeenFromMap(pre, xs.head.owner) mapOver xs.head.typeParams + val tparams = newAsSeenFromMap(pre, xs.head.owner) mapOver xs.head.typeParams val bounds = tparams map (_.tpeHK) // see e.g., #1236 val tpe = PolyType(tparams, OverloadedType(AntiPolyType(pre, bounds), xs)) diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index a1bf3a56c3..777e96da82 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -47,11 +47,23 @@ trait Namers extends MethodSynthesis { private class NormalNamer(context: Context) extends Namer(context) def newNamer(context: Context): Namer = new NormalNamer(context) - def newNamerFor(context: Context, tree: Tree): Namer = - newNamer(context.makeNewScope(tree, tree.symbol)) + def newNamerFor(context: Context, tree: Tree): Namer = newNamer(context.makeNewScope(tree, tree.symbol)) abstract class Namer(val context: Context) extends MethodSynth with NamerContextErrors { thisNamer => + def saveDefaultGetter(meth: Symbol, default: Symbol) { + if (forInteractive) { + // save the default getters as attachments in the method symbol. if compiling the + // same local block several times (which can happen in interactive mode) we might + // otherwise not find the default symbol, because the second time it the method + // symbol will be re-entered in the scope but the default parameter will not. + meth.attachments.get[DefaultsOfLocalMethodAttachment] match { + case Some(att) => att.defaultGetters += default + case None => meth.updateAttachment(new DefaultsOfLocalMethodAttachment(default)) + } + } + } + import NamerErrorGen._ val typer = newTyper(context) @@ -1297,17 +1309,10 @@ trait Namers extends MethodSynthesis { if (!isConstr) methOwner.resetFlag(INTERFACE) // there's a concrete member now val default = parentNamer.enterSyntheticSym(defaultTree) - if (forInteractive && default.owner.isTerm) { - // save the default getters as attachments in the method symbol. if compiling the - // same local block several times (which can happen in interactive mode) we might - // otherwise not find the default symbol, because the second time it the method - // symbol will be re-entered in the scope but the default parameter will not. - meth.attachments.get[DefaultsOfLocalMethodAttachment] match { - case Some(att) => att.defaultGetters += default - case None => meth.updateAttachment(new DefaultsOfLocalMethodAttachment(default)) - } - } - } else if (baseHasDefault) { + if (default.owner.isTerm) + saveDefaultGetter(meth, default) + } + else if (baseHasDefault) { // the parameter does not have a default itself, but the // corresponding parameter in the base class does. sym.setFlag(DEFAULTPARAM) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 959c5a0eb8..1a3c20c4b9 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -86,8 +86,6 @@ trait Typers extends Adaptations with Tags { // that are turned private by typedBlock private final val SYNTHETIC_PRIVATE = TRANS_FLAG - private def isPastTyper = phase.id > currentRun.typerPhase.id - // To enable decent error messages when the typer crashes. // TODO - this only catches trees which go through def typed, // but there are all kinds of back ways - typedClassDef, etc. etc. @@ -98,13 +96,18 @@ trait Typers extends Adaptations with Tags { // - we may virtualize matches (if -Xexperimental and there's a suitable __match in scope) // - we synthesize PartialFunction implementations for `x => x match {...}` and `match {...}` when the expected type is PartialFunction // this is disabled by: interactive compilation (we run it for scaladoc due to SI-5933) - private def newPatternMatching = !forInteractive //&& !forScaladoc && (phase.id < currentRun.uncurryPhase.id) + protected def newPatternMatching = !forInteractive //&& !forScaladoc && (phase.id < currentRun.uncurryPhase.id) abstract class Typer(context0: Context) extends TyperDiagnostics with Adaptation with Tag with TyperContextErrors { import context0.unit import typeDebug.{ ptTree, ptBlock, ptLine } import TyperErrorGen._ + /** (Will be) overridden to false in scaladoc and/or interactive. */ + def canAdaptConstantTypeToLiteral = !forScaladoc && !forInteractive + def canTranslateEmptyListToNil = !forInteractive + def missingSelectErrorTree(tree: Tree, qual: Tree, name: Name): Tree = tree + def typedDocDef(docDef: DocDef, mode: Mode, pt: Type): Tree = typed(docDef.definition, mode, pt) @@ -3262,7 +3265,7 @@ trait Typers extends Adaptations with Tags { * forced during kind-arity checking, so it is guarded by additional * tests to ensure we're sufficiently far along. */ - if (args.isEmpty && !forInteractive && fun.symbol.isInitialized && ListModule.hasCompleteInfo && (fun.symbol == List_apply)) + if (args.isEmpty && canTranslateEmptyListToNil && fun.symbol.isInitialized && ListModule.hasCompleteInfo && (fun.symbol == List_apply)) atPos(tree.pos)(gen.mkNil setType restpe) else constfold(treeCopy.Apply(tree, fun, args1) setType ifPatternSkipFormals(restpe)) @@ -5255,7 +5258,6 @@ trait Typers extends Adaptations with Tags { case tree: ApplyDynamic => typedApplyDynamic(tree) case tree: ReferenceToBoxed => typedReferenceToBoxed(tree) case tree: TypeTreeWithDeferredRefCheck => tree // TODO: retype the wrapped tree? TTWDRC would have to change to hold the wrapped tree (not a closure) - case tree: Import => assert(forInteractive, "!forInteractive") ; tree setType tree.symbol.tpe // should not happen in normal circumstances. case _ => abort(s"unexpected tree: ${tree.getClass}\n$tree") } } diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index df9d907377..3bde280681 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -283,7 +283,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => val file = new BatchSourceFile("", wrappedCode) val unit = new CompilationUnit(file) phase = run.parserPhase - val parser = new syntaxAnalyzer.UnitParser(unit) + val parser = newUnitParser(unit) val wrappedTree = parser.parse() throwIfErrors() val PackageDef(_, List(ModuleDef(_, _, Template(_, _, _ :: parsed)))) = wrappedTree diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 26ca62c44a..f7a87d2700 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -69,6 +69,20 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ val originalOwner = perRunCaches.newMap[Symbol, Symbol]() + // TODO - don't allow the owner to be changed without checking invariants, at least + // when under some flag. Define per-phase invariants for owner/owned relationships, + // e.g. after flatten all classes are owned by package classes, there are lots and + // lots of these to be declared (or more realistically, discovered.) + protected def saveOriginalOwner(sym: Symbol) { + // don't keep the original owner in presentation compiler runs + // (the map will grow indefinitely, and the only use case is the + // backend). + if (!forInteractive) { + if (originalOwner contains sym) () + else originalOwner(sym) = sym.rawowner + } + } + abstract class SymbolContextApiImpl extends SymbolContextApi { this: Symbol => @@ -948,13 +962,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => // e.g. after flatten all classes are owned by package classes, there are lots and // lots of these to be declared (or more realistically, discovered.) def owner_=(owner: Symbol) { - // don't keep the original owner in presentation compiler runs - // (the map will grow indefinitely, and the only use case is the - // backend). - if (!forInteractive) { - if (originalOwner contains this) () - else originalOwner(this) = rawowner - } + saveOriginalOwner(this) assert(isCompilerUniverse, "owner_= is not thread-safe; cannot be run in reflexive code") if (traceSymbolActivity) traceSymbols.recordNewSymbolOwner(this, owner) -- cgit v1.2.3