From e01c7eff032150f8460a76700542c214847ba115 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Wed, 6 Mar 2013 09:20:18 -0800 Subject: Moved interactive code into src/interactive. As with scaladoc, pushes presentation compiler specific code into its separate source area. --- .../scala/tools/nsc/interactive/Global.scala | 85 +++++++++++++++++++++- .../scala/tools/nsc/interactive/Main.scala | 34 +++++++++ 2 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 src/interactive/scala/tools/nsc/interactive/Main.scala diff --git a/src/interactive/scala/tools/nsc/interactive/Global.scala b/src/interactive/scala/tools/nsc/interactive/Global.scala index 33b10d1a9a..6abbd1b3ba 100644 --- a/src/interactive/scala/tools/nsc/interactive/Global.scala +++ b/src/interactive/scala/tools/nsc/interactive/Global.scala @@ -14,11 +14,69 @@ import scala.tools.nsc.util.MultiHashMap import scala.reflect.internal.util.{ SourceFile, BatchSourceFile, Position, NoPosition } import scala.tools.nsc.reporters._ import scala.tools.nsc.symtab._ -import scala.tools.nsc.typechecker.DivergentImplicit +import scala.tools.nsc.typechecker.{ Analyzer, DivergentImplicit } import symtab.Flags.{ACCESSOR, PARAMACCESSOR} -import scala.annotation.elidable +import scala.annotation.{ elidable, tailrec } import scala.language.implicitConversions +trait InteractiveAnalyzer extends Analyzer { + val global : Global + import global._ + + override def newTyper(context: Context): InteractiveTyper = new Typer(context) with InteractiveTyper + override def newNamer(context: Context): InteractiveNamer = new Namer(context) with InteractiveNamer + override protected def newPatternMatching = false + + trait InteractiveTyper extends Typer { + override def canAdaptConstantTypeToLiteral = false + override def canTranslateEmptyListToNil = false + override def missingSelectErrorTree(tree: Tree, qual: Tree, name: Name): Tree = tree match { + case Select(_, _) => treeCopy.Select(tree, qual, name) + case SelectFromTypeTree(_, _) => treeCopy.SelectFromTypeTree(tree, qual, name) + } + } + + trait InteractiveNamer extends Namer { + override def saveDefaultGetter(meth: Symbol, default: Symbol) { + // 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)) + } + } + // this logic is needed in case typer was interrupted half + // way through and then comes back to do the tree again. In + // that case the definitions that were already attributed as + // well as any default parameters of such methods need to be + // re-entered in the current scope. + override def enterExistingSym(sym: Symbol): Context = { + if (sym != null && sym.owner.isTerm) { + enterIfNotThere(sym) + if (sym.isLazy) + sym.lazyAccessor andAlso enterIfNotThere + + for (defAtt <- sym.attachments.get[DefaultsOfLocalMethodAttachment]) + defAtt.defaultGetters foreach enterIfNotThere + } + super.enterExistingSym(sym) + } + override def enterIfNotThere(sym: Symbol) { + val scope = context.scope + @tailrec def search(e: ScopeEntry) { + if ((e eq null) || (e.owner ne scope)) + scope enter sym + else if (e.sym ne sym) // otherwise, aborts since we found sym + search(e.tail) + } + search(scope lookupEntry sym.name) + } + } +} + + /** The main class of the presentation compiler in an interactive environment such as an IDE */ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") extends { @@ -68,8 +126,25 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") @inline final def informIDE(msg: => String) = if (verboseIDE) println("[%s][%s]".format(projectName, msg)) + // don't keep the original owner in presentation compiler runs + // (the map will grow indefinitely, and the only use case is the + // backend). + override protected def saveOriginalOwner(sym: Symbol) { } + override def forInteractive = true + override def newAsSeenFromMap(pre: Type, clazz: Symbol): AsSeenFromMap = + new InteractiveAsSeenFromMap(pre, clazz) + + class InteractiveAsSeenFromMap(pre: Type, clazz: Symbol) extends AsSeenFromMap(pre, clazz) { + /** The method formerly known as 'instParamsRelaxed' goes here if it's still necessary, + * which it is currently supposed it is not. + * + * If it is, change AsSeenFromMap method correspondingTypeArgument to call an overridable + * method rather than aborting in the failure case. + */ + } + /** A map of all loaded files to the rich compilation units that correspond to them. */ val unitOfFile = new LinkedHashMap[AbstractFile, RichCompilationUnit] with @@ -127,6 +202,10 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") } } + override lazy val analyzer = new { + val global: Global.this.type = Global.this + } with InteractiveAnalyzer + private def cleanAllResponses() { cleanResponses(waitLoadedTypeResponses) cleanResponses(getParsedEnteredResponses) @@ -281,7 +360,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") * top-level idents. Therefore, we can detect top-level symbols that have a name * different from their source file */ - override lazy val loaders = new BrowsingLoaders { + override lazy val loaders: SymbolLoaders { val global: Global.this.type } = new BrowsingLoaders { val global: Global.this.type = Global.this } diff --git a/src/interactive/scala/tools/nsc/interactive/Main.scala b/src/interactive/scala/tools/nsc/interactive/Main.scala new file mode 100644 index 0000000000..3b4a36f62d --- /dev/null +++ b/src/interactive/scala/tools/nsc/interactive/Main.scala @@ -0,0 +1,34 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2013 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.tools +package nsc +package interactive + +/** The main class for NSC, a compiler for the programming + * language Scala. + */ +object Main extends nsc.MainClass { + override def processSettingsHook(): Boolean = { + if (this.settings.Yidedebug.value) { + this.settings.Xprintpos.value = true + this.settings.Yrangepos.value = true + val compiler = new interactive.Global(this.settings, this.reporter) + import compiler.{ reporter => _, _ } + + val sfs = command.files map getSourceFile + val reloaded = new interactive.Response[Unit] + askReload(sfs, reloaded) + + reloaded.get.right.toOption match { + case Some(ex) => reporter.cancelled = true // Causes exit code to be non-0 + case None => reporter.reset() // Causes other compiler errors to be ignored + } + askShutdown + false + } + else true + } +} -- cgit v1.2.3