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

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

package dotty.tools.dotc
package transform

import core._
import typer._
import ast.Trees._
import Contexts._
import Symbols._
import Decorators._
import collection.mutable
import annotation.tailrec

/** A Macrotransform that maintains the necessary infrastructore to support
 *  contxtual implicit searches (type-scope implicits are supported anyway).
 */
abstract class MacroTransformWithImplicits extends MacroTransform {
  import ast.tpd._

  override def allowsImplicitSearch = true

  class ImplicitsTransformer extends Transformer {

    /** 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
     */
    override 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
    }

    override def transform(tree: Tree)(implicit ctx: Context): Tree = {
      def localCtx = ctx.withOwner(tree.symbol)
      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 _ =>
          super.transform(tree)
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy