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

scala.tools.nsc.interpreter.ReplGlobal.scala Maven / Gradle / Ivy

The newest version!
/*
 * Scala (https://www.scala-lang.org)
 *
 * Copyright EPFL and Lightbend, Inc.
 *
 * Licensed under Apache License 2.0
 * (http://www.apache.org/licenses/LICENSE-2.0).
 *
 * See the NOTICE file distributed with this work for
 * additional information regarding copyright ownership.
 */

package scala.tools.nsc
package interpreter

import scala.reflect.internal.util.AbstractFileClassLoader
import scala.tools.nsc.classpath.{AggregateClassPath, ClassPathFactory}
import scala.tools.nsc.transform.Transform
import scala.tools.nsc.util.ClassPath

trait ReplGlobal extends Global {
  self =>

  override def abort(msg: String): Nothing = {
    // Using the reporter too early leads to deadlock. TODO: is this still true?
    Console.println("ReplGlobal.abort: " + msg)
    super.abort(msg)
  }

  override def findMacroClassLoader(): ClassLoader = {
    val loader = super.findMacroClassLoader()
    analyzer.macroLogVerbose(s"macro classloader: initializing from a REPL classloader: ${classPath.asURLs}")
    val virtualDirectory = analyzer.globalSettings.outputDirs.getSingleOutput.get
    new AbstractFileClassLoader(virtualDirectory, loader) {}
  }

  private var seenFeatureNames = Set.empty[String]

  override def PerRunReporting = new PerRunReporting {
    override def featureWarning(pos: Position, featureName: String, featureDesc: String, featureTrait: Symbol, construct: => String, required: Boolean, site: Symbol): Unit = {
      if (seenFeatureNames(featureName)) featureReported(featureTrait)
      else seenFeatureNames += featureName
      super.featureWarning(pos, featureName, featureDesc, featureTrait, construct, required, site)
    }
  }

  override protected def computeInternalPhases(): Unit = {
    super.computeInternalPhases()
    addToPhasesSet(wrapperCleanup, "Remove unused values from import wrappers to avoid unwanted capture of non-serializable objects")
  }

  private val PositiveInt = """\d+""".r

  /** Is the given name of the form created by `lineReadValName`? */
  private def isLineReadVal(name: Global#Name) = {
    import Naming.sessionNames._
    name.startsWith(line) && name.endsWith(read) && (name.subSequence(line.length, name.length - read.length) match {
      case PositiveInt() => true
      case _ => false
    })
  }

  private object wrapperCleanup extends Transform {
    override val global: self.type = self
    override val phaseName: String = "wrapper-cleanup"
    /** Names of phases that must run before this phase. */
    override val runsAfter: List[String] = List("refchecks")
    /** Names of phases that must run after this phase. Default is `Nil`. */
    override val runsBefore: List[String] = List("uncurry")
    /** Name of the phase that this phase must follow immediately. */
    override val runsRightAfter: Option[String] = None
    override protected def newTransformer(unit: CompilationUnit): AstTransformer = new WrapperCleanupTransformer
    class WrapperCleanupTransformer extends AstTransformer {
      override def transformUnit(unit: CompilationUnit): Unit = {
        if (settings.Yreplclassbased.value) super.transformUnit(unit)
      }

      def newUnusedPrivates: analyzer.UnusedPrivates = new analyzer.UnusedPrivates() {
        override def isEffectivelyPrivate(sym: Symbol): Boolean = isLineReadVal(sym.name)
      }

      override def transform(tree: Tree): Tree = super.transform(tree) match {
        case tpl @ Template(_, _, body) if nme.isReplWrapperName(tpl.symbol.name) =>
          val unusedPrivates = newUnusedPrivates
          unusedPrivates.traverse(tpl)
          val unusedSyms = unusedPrivates.unusedTerms.iterator.map(_.symbol)
          val unusedLineReadVals = unusedSyms.filter(sym => isLineReadVal(sym.name)).flatMap(sym => List(sym, sym.accessedOrSelf)).toSet
          val (removedStats, retainedStats) = body.partition(stat => unusedLineReadVals(stat.symbol))
          if (removedStats.isEmpty) tpl
          else {
            val decls = tpl.symbol.info.decls
            removedStats.foreach(stat => decls.unlink(stat.symbol))
            deriveTemplate(tpl)(_ => retainedStats)
          }
        case transformed => transformed
      }
    }
  }

  override def optimizerClassPath(base: ClassPath): ClassPath = {
    val base1 = super.optimizerClassPath(base)
    settings.outputDirs.getSingleOutput match {
      case None => base1
      case Some(out) =>
        // Make bytecode of previous lines available to the inliner
        val replOutClasspath = ClassPathFactory.newClassPath(settings.outputDirs.getSingleOutput.get, settings, closeableRegistry)
        AggregateClassPath.createAggregate(base1, replOutClasspath)
    }
  }

  override def toString = ""
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy