All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dotty.tools.dotc.transform.LinkAll.scala Maven / Gradle / Ivy

package dotty.tools.dotc.transform

import dotty.tools.dotc.CompilationUnit
import dotty.tools.dotc.ast.Trees._
import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.core.Phases.Phase
import dotty.tools.dotc.core.Contexts._
import dotty.tools.dotc.core.SymDenotations.ClassDenotation
import dotty.tools.dotc.core.Symbols._
import dotty.tools.dotc.core.Flags._
import dotty.tools.dotc.core.Mode

/** Loads all potentially reachable trees from tasty. ▲
 *  Only performed on whole world optimization mode. ▲ ▲
 *
 *  TODO: Next step is to only load compilation units reachable in the call graph
 */
class LinkAll extends Phase {
  import tpd._
  import LinkAll._

  def phaseName: String = LinkAll.name

  def run(implicit ctx: Context): Unit = ()

  override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = {
    /** Loads and processes new compilation units, possibly loading more units. */
    def allUnits(processed: Set[CompilationUnit], unprocessed: Set[CompilationUnit], loadedClasses: Set[ClassDenotation])(implicit ctx: Context): List[CompilationUnit] = {
      if (unprocessed.isEmpty) processed.toList
      else {
        val accum = new ClassesToLoadAccumulator
        val classesToLoad = unprocessed.foldLeft(Set.empty[ClassDenotation])((acc, unit) => accum.apply(acc, unit.tpdTree)) -- loadedClasses
        val loadedUnits = classesToLoad.flatMap(cls => loadCompilationUnit(cls))
        allUnits(processed ++ unprocessed, loadedUnits, loadedClasses ++ classesToLoad)
      }
    }

    if (ctx.settings.Xlink.value) allUnits(Set.empty, units.toSet, Set.empty)
    else units
  }

  /** Collects all class denotations that may need to be loaded. */
  private class ClassesToLoadAccumulator extends TreeAccumulator[Set[ClassDenotation]] {
    private[this] var inParents = false
    override def apply(acc: Set[ClassDenotation], tree: tpd.Tree)(implicit ctx: Context): Set[ClassDenotation] = tree match {
      case New(tpt) => accum(acc, tpt.tpe.classSymbol)
      case AppliedTypeTree(tpt, _) if inParents => accum(acc, tpt.symbol)
      case tree: RefTree if inParents || tree.symbol.is(Module) =>
        foldOver(accum(acc, tree.symbol), tree)
      case tree @ Template(constr, parents, self, _) =>
        val acc1 = this(acc, constr)
        inParents = true
        val acc2 = this(acc1, parents)
        inParents = false
        this(this(acc2, self), tree.body)
      case _ => foldOver(acc, tree)
    }

    /** Accumulate class denotation for `sym` if needed */
    private def accum(acc: Set[ClassDenotation], sym: Symbol)(implicit ctx: Context): Set[ClassDenotation] = {
      val topClass = sym.topLevelClass.denot.asClass
      if (topClass.is(JavaDefined) || topClass.is(Scala2x) || topClass.symbol == defn.ObjectClass) acc
      else acc + topClass
    }
  }
}

object LinkAll {

  val name = "linkAll"

  private[LinkAll] def loadCompilationUnit(clsd: ClassDenotation)(implicit ctx: Context): Option[CompilationUnit] = {
    assert(ctx.settings.Xlink.value)
    val tree = clsd.symbol.asClass.tree(ctx.addMode(Mode.ReadPositions))
    if (tree.isEmpty) None
    else {
      ctx.log("Loading compilation unit for: " + clsd)
      Some(CompilationUnit.mkCompilationUnit(clsd, tree, forceTrees = false))
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy