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

dotty.tools.dotc.transform.localopt.Valify.scala Maven / Gradle / Ivy

package dotty.tools.dotc
package transform.localopt

import core.Contexts.Context
import core.Symbols._
import core.Types._
import core.Flags._
import ast.Trees._
import scala.collection.mutable

/** Rewrite vars with exactly one assignment as vals.
 *
 *  @author DarkDimius, OlivierBlanvillain
 */
class Valify(val simplifyPhase: Simplify) extends Optimisation {
  import ast.tpd._

  // Either a duplicate or a read through series of immutable fields.
  val defined: MutableSymbolMap[ValDef] = newMutableSymbolMap

  val firstRead: MutableSymbolMap[RefTree] = newMutableSymbolMap

  val firstWrite: MutableSymbolMap[Assign] = newMutableSymbolMap

  val secondWrite: MutableSymbolMap[Assign] = newMutableSymbolMap

  def clear(): Unit = {
    defined.clear()
    firstRead.clear()
    firstWrite.clear()
    secondWrite.clear()
  }

  def visitor(implicit ctx: Context): Tree => Unit = {
    case t: ValDef if t.symbol.is(Mutable, Lazy) && !t.symbol.is(Method) && !t.symbol.owner.isClass =>
      if (isPureExpr(t.rhs))
        defined(t.symbol) = t

    case t: RefTree if t.symbol.exists && !t.symbol.is(Method) && !t.symbol.owner.isClass =>
      if (!firstWrite.contains(t.symbol)) firstRead(t.symbol) = t

    case t @ Assign(l, expr) if !l.symbol.is(Method) && !l.symbol.owner.isClass =>
      if (!firstRead.contains(l.symbol)) {
        if (firstWrite.contains(l.symbol)) {
          if (!secondWrite.contains(l.symbol))
            secondWrite(l.symbol) = t
        } else if (!expr.existsSubTree(x => x match {
          case tree: RefTree if x.symbol == l.symbol => firstRead(l.symbol) = tree; true
          case _ => false
        })) {
          firstWrite(l.symbol) = t
        }
      }
    case _ =>
  }

  def transformer(implicit ctx: Context): Tree => Tree = {
    case t: Block => // Drop non-side-effecting stats
      val valdefs = t.stats.collect {
        case t: ValDef if defined.contains(t.symbol) => t
      }

      val assigns = t.stats.filter {
        case t @ Assign(lhs, r) =>
          firstWrite.contains(lhs.symbol) && !secondWrite.contains(lhs.symbol)
        case _ => false
      }

      val pairs = valdefs.flatMap(x => assigns.find(y => y.asInstanceOf[Assign].lhs.symbol == x.symbol) match {
        case Some(y: Assign) => List((x, y))
        case _ => Nil
      })

      val valsToDrop = pairs.map(_._1).toSet
      val assignsToReplace: Map[Assign, ValDef] = pairs.map(_.swap).toMap

      val newStats = t.stats.mapConserve {
        case x: ValDef if valsToDrop.contains(x) => EmptyTree
        case t: Assign => assignsToReplace.get(t) match {
          case Some(vd) =>
            val newD = vd.symbol.asSymDenotation.copySymDenotation(initFlags = vd.symbol.flags.&~(Mutable))
            newD.installAfter(simplifyPhase)
            ValDef(vd.symbol.asTerm, t.rhs)
          case None => t
        }
        case x => x
      }

      if (newStats eq t.stats) t
      else cpy.Block(t)(newStats, t.expr)
    case tree => tree
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy