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

dotty.tools.dotc.ast.TreeMapWithImplicits.scala Maven / Gradle / Ivy

The newest version!
package dotty.tools.dotc.ast

import dotty.tools.dotc.ast.Trees._
import dotty.tools.dotc.core.Contexts._
import dotty.tools.dotc.core.Flags._
import dotty.tools.dotc.core.Symbols._
import dotty.tools.dotc.core.TypeError

import scala.annotation.tailrec

/** A TreeMap that maintains the necessary infrastructure to support
 *  contextual implicit searches (type-scope implicits are supported anyway).
 *
 *  This incudes implicits defined in scope as well as imported implicits.
 */
class TreeMapWithImplicits extends tpd.TreeMap {
  import tpd._

  def transformSelf(vd: ValDef)(implicit ctx: Context): ValDef =
    cpy.ValDef(vd)(tpt = transform(vd.tpt))

  /** Transform statements, while maintaining import contexts and expression contexts
   *  in the same way as Typer does. The code addresses additional concerns:
   *   - be tail-recursive where possible
   *   - don't re-allocate trees where nothing has changed
   */
  def transformStats(stats: List[Tree], exprOwner: Symbol)(implicit ctx: Context): List[Tree] = {

    @tailrec def traverse(curStats: List[Tree])(implicit ctx: Context): List[Tree] = {

      def recur(stats: List[Tree], changed: Tree, rest: List[Tree])(implicit ctx: Context): List[Tree] = {
        if (stats eq curStats) {
          val rest1 = transformStats(rest, exprOwner)
          changed match {
            case Thicket(trees) => trees ::: rest1
            case tree => tree :: rest1
          }
        }
        else stats.head :: recur(stats.tail, changed, rest)
      }

      curStats match {
        case stat :: rest =>
          val statCtx = stat match {
            case stat: DefTree => ctx
            case _ => ctx.exprContext(stat, exprOwner)
          }
          val restCtx = stat match {
            case stat: Import => ctx.importContext(stat, stat.symbol)
            case _ => ctx
          }
          val stat1 = transform(stat)(statCtx)
          if (stat1 ne stat) recur(stats, stat1, rest)(restCtx)
          else traverse(rest)(restCtx)
        case nil =>
          stats
      }
    }
    traverse(stats)
  }

  private def nestedScopeCtx(defs: List[Tree])(implicit ctx: Context): Context = {
    val nestedCtx = ctx.fresh.setNewScope
    defs foreach {
      case d: DefTree => nestedCtx.enter(d.symbol)
      case _ =>
    }
    nestedCtx
  }

  private def patternScopeCtx(pattern: Tree)(implicit ctx: Context): Context = {
    val nestedCtx = ctx.fresh.setNewScope
    new TreeTraverser {
      def traverse(tree: Tree)(implicit ctx: Context): Unit = {
        tree match {
          case d: DefTree => nestedCtx.enter(d.symbol)
          case _ =>
        }
        traverseChildren(tree)
      }
    }.traverse(pattern)
    nestedCtx
  }

  override def transform(tree: Tree)(implicit ctx: Context): Tree = {
    def localCtx =
      if (tree.hasType && tree.symbol.exists) ctx.withOwner(tree.symbol) else ctx
    try tree match {
      case tree: Block =>
        super.transform(tree)(nestedScopeCtx(tree.stats))
      case tree: DefDef =>
        implicit val ctx = localCtx
        cpy.DefDef(tree)(
          tree.name,
          transformSub(tree.tparams),
          tree.vparamss mapConserve (transformSub(_)),
          transform(tree.tpt),
          transform(tree.rhs)(nestedScopeCtx(tree.vparamss.flatten)))
      case EmptyValDef =>
        tree
      case _: PackageDef | _: MemberDef =>
        super.transform(tree)(localCtx)
      case impl @ Template(constr, parents, self, _) =>
        cpy.Template(tree)(
          transformSub(constr),
          transform(parents)(ctx.superCallContext),
          Nil,
          transformSelf(self),
          transformStats(impl.body, tree.symbol))
      case tree: CaseDef =>
        val patCtx = patternScopeCtx(tree.pat)(ctx)
        cpy.CaseDef(tree)(
          transform(tree.pat),
          transform(tree.guard)(patCtx),
          transform(tree.body)(patCtx)
        )
      case _ =>
        super.transform(tree)
    }
    catch {
      case ex: TypeError =>
        ctx.error(ex.toMessage, tree.sourcePos)
        tree
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy