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

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

package dotty.tools.dotc
package transform.localopt

import core._
import core.Constants.Constant
import core.Contexts.Context
import core.Decorators._
import core.Symbols._
import core.Types._
import core.Flags._
import ast.Trees._
import transform.SymUtils._
import Simplify.isEffectivelyMutable

/** Eliminated casts and equality tests whose results can be locally
 *  determined at compile time:
 *
 *  - a.asInstanceOf[T] → a when we know that a: T
 *  - Simplify (a == null) and (a != null) when the result is statically known
 *
 *  @author DarkDimius, OlivierBlanvillain
 */
 class DropGoodCasts extends Optimisation {
  import ast.tpd._

  def visitor(implicit ctx: Context) = NoVisitor
  def clear(): Unit = ()

  def transformer(implicit ctx: Context): Tree => Tree = {
    case t @ If(cond, thenp, elsep) =>
      val newTypeTested = collectTypeTests(cond)
      val nullTested = collectNullTests(cond).toSet
      val testedMap = newTypeTested.foldRight[Map[Symbol, List[Type]]](Map.empty) { case (x, y) =>
        y + ((x._1, x._2 :: y.getOrElse(x._1, Nil)))
      }
      val dropGoodCastsInStats = new TreeMap() {
        override def transform(tree: Tree)(implicit ctx: Context): Tree = {
          def applyCondition(fun: Select, tree: Tree, const: Constant): Boolean =
            const.tag == Constants.NullTag &&
            (fun.symbol == defn.Object_eq || fun.symbol == defn.Object_ne) &&
            (nullTested.contains(tree.symbol))

          def applyBody(fun: Select): Tree =
            if (fun.symbol == defn.Object_eq) Literal(Constant(false))
            else Literal(Constant(true))

          super.transform(tree) match {
            case t: Block =>
              val nstats = t.stats.filterConserve({
                case TypeApply(fun @ Select(rec, _), List(tp))
                  if fun.symbol == defn.Any_asInstanceOf =>
                    !testedMap.getOrElse(rec.symbol, Nil).exists(x => x <:< tp.tpe)
                case _ => true
              })
              if (nstats eq t.stats) t
              else Block(nstats, t.expr)
            case Apply(fun @ Select(lhs, _), List(Literal(const))) if applyCondition(fun, lhs, const) =>
              applyBody(fun)
            case Apply(fun @ Select(Literal(const), _), List(rhs)) if applyCondition(fun, rhs, const) =>
              applyBody(fun)
            case t => t
          }
        }
      }
      val nthenp = dropGoodCastsInStats.transform(thenp)

      cpy.If(t)(thenp = nthenp, elsep = elsep)
    case t => t
  }

  def collectTypeTests(t: Tree)(implicit ctx: Context): List[(Symbol, Type)] = {
    def recur(t: Tree): List[(Symbol, Type)] =
      t match {
        case Apply(x, _) if (x.symbol == defn.Boolean_! || x.symbol == defn.Boolean_||) =>
          Nil

        case Apply(fun @ Select(x, _), y) if (fun.symbol == defn.Boolean_&&) =>
          recur(x) ++ recur(y.head)

        case TypeApply(fun @ Select(x, _), List(tp))
          if fun.symbol.eq(defn.Any_isInstanceOf) &&
             !isEffectivelyMutable(x)             &&
             !x.symbol.is(Method)                 &&
             x.symbol.exists && !x.symbol.owner.isClass =>
          (x.symbol, tp.tpe) :: Nil

        case _ => Nil
      }
    recur(t)
  }

  def collectNullTests(t: Tree)(implicit ctx: Context): List[Symbol] = {
    def recur(t: Tree): List[Symbol] =
      t match {
        case Apply(x, _) if (x.symbol == defn.Boolean_! || x.symbol == defn.Boolean_||) =>
          Nil

        case Apply(fun @ Select(x, _), y) if (fun.symbol == defn.Boolean_&&) =>
          recur(x) ++ recur(y.head)

        case Apply(fun @ Select(x, _), List(tp))
            if fun.symbol.eq(defn.Object_ne)  &&
               !isEffectivelyMutable(x)       &&
               !x.symbol.is(Method)           &&
               x.symbol.exists && !x.symbol.owner.isClass =>
          x.symbol :: Nil

        case _ => Nil
      }
    recur(t)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy