diff --git a/compiler/src/dotty/tools/backend/sjs/GenSJSIR.scala b/compiler/src/dotty/tools/backend/sjs/GenSJSIR.scala index 6088c86c1ffd..0659eb8d6f09 100644 --- a/compiler/src/dotty/tools/backend/sjs/GenSJSIR.scala +++ b/compiler/src/dotty/tools/backend/sjs/GenSJSIR.scala @@ -8,8 +8,9 @@ import Phases._ class GenSJSIR extends Phase { def phaseName: String = "genSJSIR" - def run(implicit ctx: Context): Unit = { - if (ctx.settings.scalajs.value) - new JSCodeGen().run() - } + override def isRunnable(implicit ctx: Context): Boolean = + super.isRunnable && ctx.settings.scalajs.value + + def run(implicit ctx: Context): Unit = + new JSCodeGen().run() } diff --git a/compiler/src/dotty/tools/dotc/consumetasty/TastyFromClass.scala b/compiler/src/dotty/tools/dotc/consumetasty/TastyFromClass.scala index fdbc6d4d79fc..c5e5e98d810e 100644 --- a/compiler/src/dotty/tools/dotc/consumetasty/TastyFromClass.scala +++ b/compiler/src/dotty/tools/dotc/consumetasty/TastyFromClass.scala @@ -8,7 +8,7 @@ import scala.tasty.file.TastyConsumer class TastyFromClass(consumer: TastyConsumer) extends TASTYCompiler { override protected def frontendPhases: List[List[Phase]] = - List(new ReadTastyTreesFromClasses) :: // Load classes from tasty + List(new ReadTasty) :: // Load classes from tasty Nil override protected def picklerPhases: List[List[Phase]] = Nil diff --git a/compiler/src/dotty/tools/dotc/core/Phases.scala b/compiler/src/dotty/tools/dotc/core/Phases.scala index 5468cef6e01b..60fcbe2acdb8 100644 --- a/compiler/src/dotty/tools/dotc/core/Phases.scala +++ b/compiler/src/dotty/tools/dotc/core/Phases.scala @@ -262,7 +262,7 @@ object Phases { final def isAfterTyper(phase: Phase): Boolean = phase.id > typerPhase.id } - trait Phase { + abstract class Phase { /** A name given to the `Phase` that can be used to debug the compiler. For * instance, it is possible to print trees after a given phase using: diff --git a/compiler/src/dotty/tools/dotc/decompiler/TASTYDecompiler.scala b/compiler/src/dotty/tools/dotc/decompiler/TASTYDecompiler.scala index 4601ff9d1a12..62f3e75d2001 100644 --- a/compiler/src/dotty/tools/dotc/decompiler/TASTYDecompiler.scala +++ b/compiler/src/dotty/tools/dotc/decompiler/TASTYDecompiler.scala @@ -11,7 +11,7 @@ import dotty.tools.dotc.core.Phases.Phase class TASTYDecompiler extends TASTYCompiler { override protected def frontendPhases: List[List[Phase]] = - List(new ReadTastyTreesFromClasses) :: // Load classes from tasty + List(new ReadTasty) :: // Load trees from TASTY files Nil override protected def picklerPhases: List[List[Phase]] = Nil diff --git a/compiler/src/dotty/tools/dotc/fromtasty/ReadTastyTreesFromClasses.scala b/compiler/src/dotty/tools/dotc/fromtasty/ReadTasty.scala similarity index 90% rename from compiler/src/dotty/tools/dotc/fromtasty/ReadTastyTreesFromClasses.scala rename to compiler/src/dotty/tools/dotc/fromtasty/ReadTasty.scala index b102555f35f1..13fac7bbc19d 100644 --- a/compiler/src/dotty/tools/dotc/fromtasty/ReadTastyTreesFromClasses.scala +++ b/compiler/src/dotty/tools/dotc/fromtasty/ReadTasty.scala @@ -7,14 +7,19 @@ import Decorators._ import Contexts.Context import Symbols.{Symbol, ClassSymbol} import SymDenotations.ClassDenotation -import typer.FrontEnd import NameOps._ import ast.Trees.Tree import CompilationUnit.mkCompilationUnit +import Phases.Phase -class ReadTastyTreesFromClasses extends FrontEnd { - override def isTyper: Boolean = false +/** Load trees from TASTY files */ +class ReadTasty extends Phase { + + def phaseName: String = "readTasty" + + override def isRunnable(implicit ctx: Context): Boolean = + ctx.settings.fromTasty.value override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = units.flatMap(readTASTY(_)(ctx.addMode(Mode.ReadPositions))) @@ -71,4 +76,6 @@ class ReadTastyTreesFromClasses extends FrontEnd { case unit => Some(unit) } + + def run(implicit ctx: Context): Unit = unsupported("run") } diff --git a/compiler/src/dotty/tools/dotc/fromtasty/TASTYCompiler.scala b/compiler/src/dotty/tools/dotc/fromtasty/TASTYCompiler.scala index 31d3d965682b..649580dcf772 100644 --- a/compiler/src/dotty/tools/dotc/fromtasty/TASTYCompiler.scala +++ b/compiler/src/dotty/tools/dotc/fromtasty/TASTYCompiler.scala @@ -10,10 +10,7 @@ import dotty.tools.dotc.transform._ class TASTYCompiler extends Compiler { override protected def frontendPhases: List[List[Phase]] = - List(new ReadTastyTreesFromClasses) :: Nil - - override protected def picklerPhases: List[List[Phase]] = - super.picklerPhases.map(_.filterNot(_.isInstanceOf[Pickler])) // No need to repickle + List(new ReadTasty) :: Nil override def newRun(implicit ctx: Context): Run = { reset() diff --git a/compiler/src/dotty/tools/dotc/quoted/QuoteCompiler.scala b/compiler/src/dotty/tools/dotc/quoted/QuoteCompiler.scala index 21b442ac4dfc..ad5a81b89f69 100644 --- a/compiler/src/dotty/tools/dotc/quoted/QuoteCompiler.scala +++ b/compiler/src/dotty/tools/dotc/quoted/QuoteCompiler.scala @@ -1,4 +1,5 @@ -package dotty.tools.dotc +package dotty.tools +package dotc package quoted import dotty.tools.dotc.ast.tpd @@ -14,7 +15,6 @@ import dotty.tools.dotc.core.Symbols.defn import dotty.tools.dotc.core.Types.ExprType import dotty.tools.dotc.core.quoted.PickledQuotes import dotty.tools.dotc.transform.Staging -import dotty.tools.dotc.typer.FrontEnd import dotty.tools.dotc.util.Positions.Position import dotty.tools.dotc.util.SourceFile import dotty.tools.io.{Path, VirtualFile} @@ -40,10 +40,10 @@ class QuoteCompiler extends Compiler { def outputClassName: TypeName = "Quoted".toTypeName /** Frontend that receives a scala.quoted.Expr or scala.quoted.Type as input */ - class QuotedFrontend(putInClass: Boolean) extends FrontEnd { + class QuotedFrontend(putInClass: Boolean) extends Phase { import tpd._ - override def isTyper: Boolean = false + def phaseName: String = "quotedFrontend" override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = { units.map { @@ -80,6 +80,8 @@ class QuoteCompiler extends Compiler { val classTree = ClassDef(cls, DefDef(cls.primaryConstructor.asTerm), run :: Nil) PackageDef(ref(defn.RootPackage).asInstanceOf[Ident], classTree :: Nil).withPos(pos) } + + def run(implicit ctx: Context): Unit = unsupported("run") } class ExprRun(comp: Compiler, ictx: Context) extends Run(comp, ictx) { @@ -92,5 +94,4 @@ class QuoteCompiler extends Compiler { compileUnits(units) } } - } diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala index 39b0d22c410c..8634ad928920 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala @@ -41,6 +41,11 @@ import scala.collection.mutable class ExtractAPI extends Phase { override def phaseName: String = "sbt-api" + override def isRunnable(implicit ctx: Context): Boolean = { + def forceRun = ctx.settings.YdumpSbtInc.value || ctx.settings.YforceSbtPhases.value + super.isRunnable && (ctx.sbtCallback != null || forceRun) + } + // SuperAccessors need to be part of the API (see the scripted test // `trait-super` for an example where this matters), this is only the case // after `PostTyper` (unlike `ExtractDependencies`, the simplication to trees @@ -50,30 +55,26 @@ class ExtractAPI extends Phase { override def run(implicit ctx: Context): Unit = { val unit = ctx.compilationUnit - val dumpInc = ctx.settings.YdumpSbtInc.value - val forceRun = dumpInc || ctx.settings.YforceSbtPhases.value - if ((ctx.sbtCallback != null || forceRun) && !unit.isJava) { - val sourceFile = unit.source.file - if (ctx.sbtCallback != null) - ctx.sbtCallback.startSource(sourceFile.file) - - val apiTraverser = new ExtractAPICollector - val classes = apiTraverser.apiSource(unit.tpdTree) - val mainClasses = apiTraverser.mainClasses - - if (dumpInc) { - // Append to existing file that should have been created by ExtractDependencies - val pw = new PrintWriter(File(sourceFile.jpath).changeExtension("inc").toFile - .bufferedWriter(append = true), true) - try { - classes.foreach(source => pw.println(DefaultShowAPI(source))) - } finally pw.close() - } + val sourceFile = unit.source.file + if (ctx.sbtCallback != null) + ctx.sbtCallback.startSource(sourceFile.file) + + val apiTraverser = new ExtractAPICollector + val classes = apiTraverser.apiSource(unit.tpdTree) + val mainClasses = apiTraverser.mainClasses + + if (ctx.settings.YdumpSbtInc.value) { + // Append to existing file that should have been created by ExtractDependencies + val pw = new PrintWriter(File(sourceFile.jpath).changeExtension("inc").toFile + .bufferedWriter(append = true), true) + try { + classes.foreach(source => pw.println(DefaultShowAPI(source))) + } finally pw.close() + } - if (ctx.sbtCallback != null) { - classes.foreach(ctx.sbtCallback.api(sourceFile.file, _)) - mainClasses.foreach(ctx.sbtCallback.mainClass(sourceFile.file, _)) - } + if (ctx.sbtCallback != null) { + classes.foreach(ctx.sbtCallback.api(sourceFile.file, _)) + mainClasses.foreach(ctx.sbtCallback.mainClass(sourceFile.file, _)) } } } diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala index f4bbbafe61b1..22b30e500e6e 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala @@ -49,6 +49,11 @@ class ExtractDependencies extends Phase { override def phaseName: String = "sbt-deps" + override def isRunnable(implicit ctx: Context): Boolean = { + def forceRun = ctx.settings.YdumpSbtInc.value || ctx.settings.YforceSbtPhases.value + super.isRunnable && (ctx.sbtCallback != null || forceRun) + } + // This phase should be run directly after `Frontend`, if it is run after // `PostTyper`, some dependencies will be lost because trees get simplified. // See the scripted test `constants` for an example where this matters. @@ -56,45 +61,39 @@ class ExtractDependencies extends Phase { override def run(implicit ctx: Context): Unit = { val unit = ctx.compilationUnit - val dumpInc = ctx.settings.YdumpSbtInc.value - val forceRun = dumpInc || ctx.settings.YforceSbtPhases.value - val shouldRun = !unit.isJava && (ctx.sbtCallback != null || forceRun) - - if (shouldRun) { - val collector = new ExtractDependenciesCollector - collector.traverse(unit.tpdTree) - - if (dumpInc) { - val deps = collector.dependencies.map(_.toString).toArray[Object] - val names = collector.usedNames.map { case (clazz, names) => s"$clazz: $names" }.toArray[Object] - Arrays.sort(deps) - Arrays.sort(names) - - val pw = io.File(unit.source.file.jpath).changeExtension("inc").toFile.printWriter() - // val pw = Console.out - try { - pw.println("Used Names:") - pw.println("===========") - names.foreach(pw.println) - pw.println() - pw.println("Dependencies:") - pw.println("=============") - deps.foreach(pw.println) - } finally pw.close() - } - - if (ctx.sbtCallback != null) { - collector.usedNames.foreach { - case (clazz, usedNames) => - val className = classNameAsString(clazz) - usedNames.names.foreach { - case (usedName, scopes) => - ctx.sbtCallback.usedName(className, usedName.toString, scopes) - } - } + val collector = new ExtractDependenciesCollector + collector.traverse(unit.tpdTree) + + if (ctx.settings.YdumpSbtInc.value) { + val deps = collector.dependencies.map(_.toString).toArray[Object] + val names = collector.usedNames.map { case (clazz, names) => s"$clazz: $names" }.toArray[Object] + Arrays.sort(deps) + Arrays.sort(names) + + val pw = io.File(unit.source.file.jpath).changeExtension("inc").toFile.printWriter() + // val pw = Console.out + try { + pw.println("Used Names:") + pw.println("===========") + names.foreach(pw.println) + pw.println() + pw.println("Dependencies:") + pw.println("=============") + deps.foreach(pw.println) + } finally pw.close() + } - collector.dependencies.foreach(recordDependency) + if (ctx.sbtCallback != null) { + collector.usedNames.foreach { + case (clazz, usedNames) => + val className = classNameAsString(clazz) + usedNames.names.foreach { + case (usedName, scopes) => + ctx.sbtCallback.usedName(className, usedName.toString, scopes) + } } + + collector.dependencies.foreach(recordDependency) } } diff --git a/compiler/src/dotty/tools/dotc/transform/Pickler.scala b/compiler/src/dotty/tools/dotc/transform/Pickler.scala index d7b92e3430ef..0abee9001ba9 100644 --- a/compiler/src/dotty/tools/dotc/transform/Pickler.scala +++ b/compiler/src/dotty/tools/dotc/transform/Pickler.scala @@ -24,6 +24,10 @@ class Pickler extends Phase { override def phaseName: String = Pickler.name + // No need to repickle trees comming from TASTY + override def isRunnable(implicit ctx: Context): Boolean = + super.isRunnable && !ctx.settings.fromTasty.value + private def output(name: String, msg: String) = { val s = new PrintStream(name) s.print(msg) diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index f4fab05d9f37..07b71670c5d4 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -90,7 +90,7 @@ class TreeChecker extends Phase with SymTransformer { def run(implicit ctx: Context): Unit = { if (ctx.settings.YtestPickler.value && ctx.phase.prev.isInstanceOf[Pickler]) ctx.echo("Skipping Ycheck after pickling with -Ytest-pickler, the returned tree contains stale symbols") - else + else if (ctx.phase.prev.isCheckable) check(ctx.base.allPhases, ctx) } diff --git a/compiler/src/dotty/tools/dotc/typer/FrontEnd.scala b/compiler/src/dotty/tools/dotc/typer/FrontEnd.scala index ff65c5b87ef6..6ce0e18ae89d 100644 --- a/compiler/src/dotty/tools/dotc/typer/FrontEnd.scala +++ b/compiler/src/dotty/tools/dotc/typer/FrontEnd.scala @@ -1,4 +1,5 @@ -package dotty.tools.dotc +package dotty.tools +package dotc package typer import core._ @@ -90,11 +91,7 @@ class FrontEnd extends Phase { unitContexts.map(_.compilationUnit).filterNot(discardAfterTyper) } - override def run(implicit ctx: Context): Unit = { - parse - enterSyms - typeCheck - } + def run(implicit ctx: Context): Unit = unsupported("run") } object FrontEnd { diff --git a/doc-tool/src/dotty/tools/dottydoc/DocCompiler.scala b/doc-tool/src/dotty/tools/dottydoc/DocCompiler.scala index eb1d0dc873d5..aac9171dbca1 100644 --- a/doc-tool/src/dotty/tools/dottydoc/DocCompiler.scala +++ b/doc-tool/src/dotty/tools/dottydoc/DocCompiler.scala @@ -6,9 +6,10 @@ import core.transform._ import dotc.core.Contexts.Context import dotc.core.Phases.Phase import dotc.core.Mode -import dotc.{Compiler, Run} +import dotc.{Compiler, CompilationUnit, Run} +import dotc.typer.FrontEnd -import dotty.tools.dotc.fromtasty.{ReadTastyTreesFromClasses, TASTYRun} +import dotty.tools.dotc.fromtasty.{ReadTasty, TASTYRun} import dotty.tools.dotc.transform.CookComments /** Custom Compiler with phases for the documentation tool @@ -29,36 +30,48 @@ class DocCompiler extends Compiler { if (ctx.settings.fromTasty.value) { reset() new TASTYRun(this, ctx.addMode(Mode.ReadPositions).addMode(Mode.ReadComments)) - } else { - super.newRun } + else + super.newRun } - override protected def frontendPhases: List[List[Phase]] = - List(new ReadTastyTreesFromClasses) :: - List(new DocFrontEnd) :: Nil - - override protected def picklerPhases: List[List[Phase]] = - Nil + /** `DocFrontEnd` uses the Dotty `FrontEnd` without discarding the AnyVal + * interfaces for Boolean, Int, Char, Long, Byte etc. + * + * If `-from-tasty` is set, then the trees and documentation will be loaded + * from TASTY. The comments will be cooked after being unpickled. + * + * It currently still throws away Java sources by overriding + * `discardAfterTyper`. + */ + private class DocFrontEnd extends FrontEnd { + override protected def discardAfterTyper(unit: CompilationUnit)(implicit ctx: Context) = + unit.isJava - override protected def transformPhases: List[List[Phase]] = - List(new CookComments) :: - List(new DocImplicitsPhase) :: - List(new DocASTPhase) :: - List(DocMiniTransformations(new UsecasePhase, - new DocstringPhase)) :: - List(DocMiniTransformations(new PackageObjectsPhase, - new LinkReturnTypes, - new LinkParamListTypes, - new LinkImplicitlyAddedTypes, - new LinkSuperTypes, - new LinkCompanions, - new AlternateConstructors, - new SortMembers)) :: - List(DocMiniTransformations(new RemoveEmptyPackages)) :: - Nil - - override protected def backendPhases: List[List[Phase]] = - List(new StatisticsPhase) :: Nil + override def isRunnable(implicit ctx: Context): Boolean = + super.isRunnable && !ctx.settings.fromTasty.value + } + override def phases: List[List[Phase]] = List( + List(new DocFrontEnd), + List(new ReadTasty), + List(new CookComments), + List(new DocImplicitsPhase), + List(new DocASTPhase), + List(DocMiniTransformations( + new UsecasePhase, + new DocstringPhase)), + List(DocMiniTransformations( + new PackageObjectsPhase, + new LinkReturnTypes, + new LinkParamListTypes, + new LinkImplicitlyAddedTypes, + new LinkSuperTypes, + new LinkCompanions, + new AlternateConstructors, + new SortMembers)), + List(DocMiniTransformations( + new RemoveEmptyPackages)), + List(new StatisticsPhase) + ) } diff --git a/doc-tool/src/dotty/tools/dottydoc/DocFrontEnd.scala b/doc-tool/src/dotty/tools/dottydoc/DocFrontEnd.scala deleted file mode 100644 index 25cd8d95b42f..000000000000 --- a/doc-tool/src/dotty/tools/dottydoc/DocFrontEnd.scala +++ /dev/null @@ -1,29 +0,0 @@ -package dotty.tools -package dottydoc - -import dotc.fromtasty.ReadTastyTreesFromClasses -import dotc.typer.{FrontEnd, Typer} -import dotc.core.Contexts.Context -import dotc.CompilationUnit - -import util.syntax.ContextWithContextDottydoc - -/** `DocFrontEnd` uses the Dotty `FrontEnd` without discarding the AnyVal - * interfaces for Boolean, Int, Char, Long, Byte etc. - * - * If `-from-tasty` is set, then the trees and documentation will be loaded - * from TASTY. The comments will be cooked after being unpickled. - * - * It currently still throws away Java sources by overriding - * `discardAfterTyper`. - */ -class DocFrontEnd extends FrontEnd { - - override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = { - if (ctx.settings.fromTasty.value) units - else super.runOn(units) - } - - override protected def discardAfterTyper(unit: CompilationUnit)(implicit ctx: Context) = - unit.isJava -} diff --git a/doc-tool/src/dotty/tools/dottydoc/core/transform.scala b/doc-tool/src/dotty/tools/dottydoc/core/transform.scala index 2be09b76c6d8..664d8cea9ccc 100644 --- a/doc-tool/src/dotty/tools/dottydoc/core/transform.scala +++ b/doc-tool/src/dotty/tools/dottydoc/core/transform.scala @@ -44,7 +44,7 @@ object transform { * ------------------------- * To delete a node in the AST, simply return an empty list from transforming method */ - trait DocMiniTransformations extends Phase { + abstract class DocMiniTransformations extends Phase { def transformations: List[DocMiniPhase] override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = { diff --git a/doc-tool/test/dotty/tools/dottydoc/DottyDocTest.scala b/doc-tool/test/dotty/tools/dottydoc/DottyDocTest.scala index 46cb123e35e6..8621354b5c97 100644 --- a/doc-tool/test/dotty/tools/dottydoc/DottyDocTest.scala +++ b/doc-tool/test/dotty/tools/dottydoc/DottyDocTest.scala @@ -45,10 +45,10 @@ trait DottyDocTest extends MessageRendering { implicit val ctx: FreshContext = freshCtx(Nil) private def compilerWithChecker(assertion: (Context, Map[String, Package]) => Unit) = new DocCompiler { - private[this] val assertionPhase: List[List[Phase]] = - List(new Phase { + override def phases = { + val assertionPhase = new Phase { def phaseName = "assertionPhase" - override def run(implicit ctx: Context): Unit = + override def run(implicit ctx: Context): Unit = { assertion(ctx, ctx.docbase.packages) if (ctx.reporter.hasErrors) { System.err.println("reporter had errors:") @@ -58,10 +58,10 @@ trait DottyDocTest extends MessageRendering { } } } - }) :: Nil - - override protected def backendPhases: List[List[Phase]] = - super.backendPhases ++ assertionPhase + } + } + super.phases :+ List(assertionPhase) + } } private def callingMethod: String =