diff --git a/compiler/src/dotty/tools/dotc/CompilationUnit.scala b/compiler/src/dotty/tools/dotc/CompilationUnit.scala index 9b12cc9ade94..0bd29fbbeb2e 100644 --- a/compiler/src/dotty/tools/dotc/CompilationUnit.scala +++ b/compiler/src/dotty/tools/dotc/CompilationUnit.scala @@ -11,6 +11,7 @@ import ast.{tpd, untpd} import tpd.{Tree, TreeTraverser} import typer.PrepareInlineable.InlineAccessors import typer.Nullables +import transform.AccessProxies import transform.SymUtils._ import core.Decorators._ import config.SourceVersion @@ -62,7 +63,7 @@ class CompilationUnit protected (val source: SourceFile) { /** Can this compilation unit be suspended */ def isSuspendable: Boolean = true - /** Suspends the compilation unit by thowing a SuspendException + /** Suspends the compilation unit by throwing a SuspendException * and recording the suspended compilation unit */ def suspend()(using Context): Nothing = @@ -85,6 +86,9 @@ class CompilationUnit protected (val source: SourceFile) { def assignmentSpans(using Context): Map[Int, List[Span]] = if myAssignmentSpans == null then myAssignmentSpans = Nullables.assignmentSpans myAssignmentSpans + + private[dotc] var inlineAccessors: InlineAccessors = null + private[dotc] var protectedAccessors: AccessProxies = null } object CompilationUnit { diff --git a/compiler/src/dotty/tools/dotc/Compiler.scala b/compiler/src/dotty/tools/dotc/Compiler.scala index 736e1b08d1e7..123f13eea91f 100644 --- a/compiler/src/dotty/tools/dotc/Compiler.scala +++ b/compiler/src/dotty/tools/dotc/Compiler.scala @@ -3,7 +3,7 @@ package dotc import core._ import Contexts._ -import typer.{TyperPhase, RefChecks} +import typer.{NamerPhase, TyperPhase, RefChecks} import parsing.Parser import Phases.Phase import transform._ @@ -38,7 +38,8 @@ class Compiler { /** Phases dealing with the frontend up to trees ready for TASTY pickling */ protected def frontendPhases: List[List[Phase]] = List(new Parser) :: // Compiler frontend: scanner, parser - List(new TyperPhase) :: // Compiler frontend: namer, typer + List(new NamerPhase) :: // Compiler frontend: namer + List(new TyperPhase) :: // Compiler frontend: typer List(new YCheckPositions) :: // YCheck positions List(new sbt.ExtractDependencies) :: // Sends information on classes' dependencies to sbt via callbacks List(new semanticdb.ExtractSemanticDB) :: // Extract info into .semanticdb files diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index a71fc3d40e92..b652a49c0381 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -1410,29 +1410,6 @@ object desugar { FunctionWithMods(params, body, Modifiers(mods)) } - /** Add annotation to tree: - * tree @fullName - * - * The annotation is usually represented as a TypeTree referring to the class - * with the given name `fullName`. However, if the annotation matches a file name - * that is still to be entered, the annotation is represented as a cascade of `Selects` - * following `fullName`. This is necessary so that we avoid reading an annotation from - * the classpath that is also compiled from source. - */ - def makeAnnotated(fullName: String, tree: Tree)(using Context): Annotated = { - val parts = fullName.split('.') - val ttree = typerPhase match { - case phase: TyperPhase if phase.stillToBeEntered(parts.last) => - val prefix = - parts.init.foldLeft(Ident(nme.ROOTPKG): Tree)((qual, name) => - Select(qual, name.toTermName)) - Select(prefix, parts.last.toTypeName) - case _ => - TypeTree(requiredClass(fullName).typeRef) - } - Annotated(tree, New(ttree, Nil)) - } - private def derivedValDef(original: Tree, named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers)(using Context) = { val vdef = ValDef(named.name.asTermName, tpt, rhs) .withMods(mods) diff --git a/compiler/src/dotty/tools/dotc/interactive/InteractiveCompiler.scala b/compiler/src/dotty/tools/dotc/interactive/InteractiveCompiler.scala index 38a93125a342..5c7fa57c5f97 100644 --- a/compiler/src/dotty/tools/dotc/interactive/InteractiveCompiler.scala +++ b/compiler/src/dotty/tools/dotc/interactive/InteractiveCompiler.scala @@ -14,6 +14,7 @@ class InteractiveCompiler extends Compiler { // after each phase group instead of waiting for the pipeline to finish. override def phases: List[List[Phase]] = List( List(new Parser), + List(new NamerPhase), List(new TyperPhase), List(new transform.SetRootTree), List(new transform.CookComments) diff --git a/compiler/src/dotty/tools/dotc/transform/ProtectedAccessors.scala b/compiler/src/dotty/tools/dotc/transform/ProtectedAccessors.scala index ccd7066e7cec..634ebffba662 100644 --- a/compiler/src/dotty/tools/dotc/transform/ProtectedAccessors.scala +++ b/compiler/src/dotty/tools/dotc/transform/ProtectedAccessors.scala @@ -57,7 +57,11 @@ class ProtectedAccessors extends MiniPhase { ctx.property(AccessorsKey).get override def prepareForUnit(tree: Tree)(using Context): Context = - ctx.fresh.setProperty(AccessorsKey, new Accessors) + var acc = ctx.compilationUnit.protectedAccessors.asInstanceOf[Accessors] + if (acc == null) + acc = new Accessors() + ctx.compilationUnit.protectedAccessors = acc + ctx.fresh.setProperty(AccessorsKey, acc) private class Accessors extends AccessProxies { val insert: Insert = new Insert { diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index 9bd293400d65..851275c61f69 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -68,7 +68,7 @@ object Inliner { && StagingContext.level == 0 && ( ctx.phase == Phases.inliningPhase - || (ctx.phase == Phases.typerPhase && needsTransparentInlining(tree)) + || (ctx.phase.isTyper && needsTransparentInlining(tree)) ) && !ctx.typer.hasInliningErrors && !ctx.base.stopInlining diff --git a/compiler/src/dotty/tools/dotc/typer/NamerPhase.scala b/compiler/src/dotty/tools/dotc/typer/NamerPhase.scala new file mode 100644 index 000000000000..b6f0b9fd4e57 --- /dev/null +++ b/compiler/src/dotty/tools/dotc/typer/NamerPhase.scala @@ -0,0 +1,78 @@ +package dotty.tools +package dotc +package typer + +import core.* +import Phases.* +import Contexts.* +import Symbols.* +import Decorators.* +import ImportInfo.withRootImports +import parsing.JavaParsers.JavaParser +import parsing.Parsers.Parser +import parsing.Parser as ParserPhase +import config.Config +import config.Printers.{ default, typr } +import util.Stats.* +import util.{ NoSourcePosition, SourcePosition } +import scala.util.control.NonFatal + +import ast.Trees.* +import dotty.tools.dotc.core.Denotations.SingleDenotation + +/** + * + * @param addRootImports Set to false in the REPL. Calling [[ImportInfo.withRootImports]] on the [[Context]] + * for each [[CompilationUnit]] causes dotty.tools.repl.ScriptedTests to fail. + */ +class NamerPhase(addRootImports: Boolean = true) extends Phase { + + override def phaseName: String = NamerPhase.name + override def isTyper: Boolean = true + + // We run TreeChecker only after type checking + override def isCheckable: Boolean = false + + override def allowsImplicitSearch: Boolean = true + + // Run regardless of parsing errors + override def isRunnable(implicit ctx: Context): Boolean = true + + def enterSyms(using Context): Unit = monitor("indexing") { + val unit = ctx.compilationUnit + ctx.typer.index(unit.untpdTree) + typr.println("entered: " + unit.source) + } + + override def runOn(units: List[CompilationUnit])(using Context): List[CompilationUnit] = + val unitContexts = + for unit <- units yield + val newCtx0 = ctx.fresh.setPhase(this.start).setCompilationUnit(unit) + val newCtx = PrepareInlineable.initContext(newCtx0) + report.inform(s"naming ${unit.source}") + if (addRootImports) + newCtx.withRootImports + else + newCtx + + unitContexts.foreach(enterSyms(using _)) + + ctx.base.parserPhase match { + case p: ParserPhase => + if p.firstXmlPos.exists && !defn.ScalaXmlPackageClass.exists then + report.error( + """To support XML literals, your project must depend on scala-xml. + |See https://github.com/scala/scala-xml for more information.""".stripMargin, + p.firstXmlPos) + case _ => + } + + + unitContexts.map(_.compilationUnit) + + def run(using Context): Unit = unsupported("run") +} + +object NamerPhase { + val name: String = "namer" +} diff --git a/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala b/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala index 8fea810921e4..17928ce3ce7b 100644 --- a/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala +++ b/compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala @@ -29,7 +29,11 @@ object PrepareInlineable { private val InlineAccessorsKey = new Property.Key[InlineAccessors] def initContext(ctx: Context): Context = - ctx.fresh.setProperty(InlineAccessorsKey, new InlineAccessors) + var acc = ctx.compilationUnit.inlineAccessors + if (acc == null) + ctx.compilationUnit.inlineAccessors = new InlineAccessors() + acc = ctx.compilationUnit.inlineAccessors + ctx.fresh.setProperty(InlineAccessorsKey, acc) def makeInlineable(tree: Tree)(using Context): Tree = ctx.property(InlineAccessorsKey).get.makeInlineable(tree) diff --git a/compiler/src/dotty/tools/dotc/typer/TyperPhase.scala b/compiler/src/dotty/tools/dotc/typer/TyperPhase.scala index bb1bfbea28e5..af25f943acda 100644 --- a/compiler/src/dotty/tools/dotc/typer/TyperPhase.scala +++ b/compiler/src/dotty/tools/dotc/typer/TyperPhase.scala @@ -31,24 +31,9 @@ class TyperPhase(addRootImports: Boolean = true) extends Phase { override def allowsImplicitSearch: Boolean = true - /** The contexts for compilation units that are parsed but not yet entered */ - private var remaining: List[Context] = Nil - - /** Does a source file ending with `.scala` belong to a compilation unit - * that is parsed but not yet entered? - */ - def stillToBeEntered(name: String): Boolean = - remaining.exists(_.compilationUnit.toString.endsWith(name + ".scala")) - // Run regardless of parsing errors override def isRunnable(implicit ctx: Context): Boolean = true - def enterSyms(using Context): Unit = monitor("indexing") { - val unit = ctx.compilationUnit - ctx.typer.index(unit.untpdTree) - typr.println("entered: " + unit.source) - } - def typeCheck(using Context): Unit = monitor("typechecking") { try val unit = ctx.compilationUnit @@ -68,13 +53,6 @@ class TyperPhase(addRootImports: Boolean = true) extends Phase { JavaChecks.check(unit.tpdTree) } - - private def firstTopLevelDef(trees: List[tpd.Tree])(using Context): Symbol = trees match - case PackageDef(_, defs) :: _ => firstTopLevelDef(defs) - case Import(_, _) :: defs => firstTopLevelDef(defs) - case (tree @ TypeDef(_, _)) :: _ => tree.symbol - case _ => NoSymbol - protected def discardAfterTyper(unit: CompilationUnit)(using Context): Boolean = unit.isJava || unit.suspended @@ -89,19 +67,6 @@ class TyperPhase(addRootImports: Boolean = true) extends Phase { else newCtx - remaining = unitContexts - while remaining.nonEmpty do - enterSyms(using remaining.head) - remaining = remaining.tail - val firstXmlPos = ctx.base.parserPhase match { - case p: ParserPhase => - if p.firstXmlPos.exists && !defn.ScalaXmlPackageClass.exists then - report.error( - """To support XML literals, your project must depend on scala-xml. - |See https://github.com/scala/scala-xml for more information.""".stripMargin, - p.firstXmlPos) - case _ => - } unitContexts.foreach(typeCheck(using _)) record("total trees after typer", ast.Trees.ntrees) diff --git a/compiler/src/dotty/tools/repl/ReplCompiler.scala b/compiler/src/dotty/tools/repl/ReplCompiler.scala index d80e9871fdee..53348b447822 100644 --- a/compiler/src/dotty/tools/repl/ReplCompiler.scala +++ b/compiler/src/dotty/tools/repl/ReplCompiler.scala @@ -14,7 +14,7 @@ import dotty.tools.dotc.core.Symbols._ import dotty.tools.dotc.reporting.Diagnostic import dotty.tools.dotc.transform.{PostTyper, Staging} import dotty.tools.dotc.typer.ImportInfo._ -import dotty.tools.dotc.typer.TyperPhase +import dotty.tools.dotc.typer.{NamerPhase, TyperPhase} import dotty.tools.dotc.util.Spans._ import dotty.tools.dotc.util.{ParsedComment, SourceFile} import dotty.tools.dotc.{CompilationUnit, Compiler, Run} @@ -33,6 +33,7 @@ import scala.collection.mutable class ReplCompiler extends Compiler { override protected def frontendPhases: List[List[Phase]] = List( + List(new NamerPhase(addRootImports = false)), List(new TyperPhase(addRootImports = false)), List(new CollectTopLevelImports), List(new PostTyper), diff --git a/docs/docs/internals/overall-structure.md b/docs/docs/internals/overall-structure.md index 73964977ba42..dc6256a298d9 100644 --- a/docs/docs/internals/overall-structure.md +++ b/docs/docs/internals/overall-structure.md @@ -98,7 +98,8 @@ phases. The current list of phases is specified in class [Compiler] as follows: /** Phases dealing with the frontend up to trees ready for TASTY pickling */ protected def frontendPhases: List[List[Phase]] = List(new Parser) :: // scanner, parser - List(new TyperPhase) :: // namer, typer + List(new NamerPhase) :: // namer + List(new TyperPhase) :: // typer List(new YCheckPositions) :: // YCheck positions List(new sbt.ExtractDependencies) :: // Sends information on classes' dependencies to sbt via callbacks List(new semanticdb.ExtractSemanticDB) :: // Extract info into .semanticdb files