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

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

package dotty.tools.dotc
package transform

import MegaPhase._
import ast.Trees._
import core._
import Contexts._, Types._, Decorators._, Denotations._, Symbols._, SymDenotations._, Names._

object Splitter {
  val name = "splitter"
}

/** Distribute applications into Block and If nodes
 */
class Splitter extends MiniPhase {
  import ast.tpd._

  override def phaseName: String = Splitter.name

  /** Distribute arguments among splitted branches */
  def distribute(tree: GenericApply[Type], rebuild: (Tree, List[Tree]) => Context => Tree)(implicit ctx: Context) = {
    def recur(fn: Tree): Tree = fn match {
      case Block(stats, expr) => Block(stats, recur(expr))
      case If(cond, thenp, elsep) => If(cond, recur(thenp), recur(elsep))
      case _ => rebuild(fn, tree.args)(ctx) withPos tree.pos
    }
    recur(tree.fun)
  }

  private def needsDistribution(fun: Tree) = fun match {
    case _: Block | _: If => true
    case _ => false
  }

  override def transformTypeApply(tree: TypeApply)(implicit ctx: Context) =
    if (needsDistribution(tree.fun))
      distribute(tree, typeApply)
    else
      tree

  override def transformApply(tree: Apply)(implicit ctx: Context) =
    if (needsDistribution(tree.fun))
      distribute(tree, apply)
    else
      tree

  private val typeApply = (fn: Tree, args: List[Tree]) => (ctx: Context) => TypeApply(fn, args)(ctx)
  private val apply     = (fn: Tree, args: List[Tree]) => (ctx: Context) => Apply(fn, args)(ctx)

/* The following is no longer necessary, since we select members on the join of an or type:
 *
  /** If we select a name, make sure the node has a symbol.
   *  If necessary, split the qualifier with type tests.
   *  Example: Assume:
   *
   *      class A { def f(x: S): T }
   *      class B { def f(x: S): T }
   *      def p(): A | B
   *
   *  Then   p().f(a)   translates to
   *
   *      val ev$1 = p()
   *      if (ev$1.isInstanceOf[A]) ev$1.asInstanceOf[A].f(a)
   *      else ev$1.asInstanceOf[B].f(a)
   */
  override def transformSelect(tree: Select)(implicit ctx: Context) = {
    val Select(qual, name) = tree

    def memberDenot(tp: Type): SingleDenotation = {
      val mbr = tp.member(name)
      if (!mbr.isOverloaded) mbr.asSingleDenotation
      else tree.tpe match {
        case tref: TermRef if !tref.signature.isOverloaded =>
          mbr.atSignature(tref.sig).checkUnique
        case _ =>
          def alts = mbr.alternatives.map(alt => i"$alt: ${alt.info}").mkString(", ")
          ctx.error(s"cannot disambiguate overloaded members $alts", tree.pos)
          NoDenotation
      }
    }

    def candidates(tp: Type): List[Symbol] = {
      val mbr = memberDenot(tp)
      if (mbr.symbol.exists) mbr.symbol :: Nil
      else tp.widen match {
        case tref: TypeRef =>
          tref.info match {
            case TypeBounds(_, hi) => candidates(hi)
            case _ => Nil
          }
        case OrType(tp1, tp2) =>
          candidates(tp1) | candidates(tp2)
        case AndType(tp1, tp2) =>
          candidates(tp1) & candidates(tp2)
        case tpw =>
          Nil
      }
    }

    def isStructuralSelect(tp: Type): Boolean = tp.stripTypeVar match {
      case tp: RefinedType => tp.refinedName == name || isStructuralSelect(tp.parent)
      case tp: TypeProxy => isStructuralSelect(tp.underlying)
      case AndType(tp1, tp2) => isStructuralSelect(tp1) || isStructuralSelect(tp2)
      case _ => false
    }

    if (tree.symbol.exists) tree
    else {
      def choose(qual: Tree, syms: List[Symbol]): Tree = {
        def testOrCast(which: Symbol, mbr: Symbol) =
          qual.select(which).appliedToType(mbr.owner.appliedRef)
        def select(sym: Symbol) = {
          val qual1 =
            if (qual.tpe derivesFrom sym.owner) qual
            else testOrCast(defn.Any_asInstanceOf, sym)
          qual1.select(sym).withPos(tree.pos)
        }
        syms match {
          case Nil =>
            def msg =
              if (isStructuralSelect(qual.tpe))
                s"cannot access member '$name' from structural type ${qual.tpe.widen.show}; use Dynamic instead"
              else
                s"no candidate symbols for ${tree.tpe.show} found in ${qual.tpe.show}"
            ctx.error(msg, tree.pos)
            tree
          case sym :: Nil =>
            select(sym)
          case sym :: syms1 =>
            If(testOrCast(defn.Any_isInstanceOf, sym), select(sym), choose(qual, syms1))
        }
      }
      evalOnce(qual)(qual => choose(qual, candidates(qual.tpe)))
    }
  }
*/
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy