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

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

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

import dotty.tools.dotc.ast.Trees._
import dotty.tools.dotc.ast.{tpd, untpd}
import dotty.tools.dotc.core.Contexts._
import dotty.tools.dotc.core.Decorators._
import dotty.tools.dotc.core.Flags._
import dotty.tools.dotc.core.Phases
import dotty.tools.dotc.core.Symbols._
import dotty.tools.dotc.util.{SourceFile, SourcePosition}

/** Ycheck inlined positions */
class YCheckPositions extends Phases.Phase {
  import tpd._

  def phaseName: String = "inlinedPositions"

  override def run(implicit ctx: Context): Unit = () // YCheck only

  override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = {
    tree match {
      case PackageDef(pid, _) if tree.symbol.owner == defn.RootClass =>
        new TreeTraverser {
          private[this] var sources: List[SourceFile] = ctx.source :: Nil
          def traverse(tree: tpd.Tree)(implicit ctx: Context): Unit = {

            // Check current context is correct
            assert(ctx.source == sources.head)
            if (!tree.isEmpty && !tree.isInstanceOf[untpd.TypedSplice] && ctx.typerState.isGlobalCommittable) {
              if (!tree.isType) { // TODO also check types, currently we do not add Inlined(EmptyTree, _, _) for types. We should.
                val currentSource = sources.head
                assert(tree.source == currentSource, i"wrong source set for $tree # ${tree.uniqueId} of ${tree.getClass}, set to ${tree.source} but context had $currentSource")
              }
            }

            // Recursivlely check children while keeping track of current source
            tree match {
              case Inlined(EmptyTree, bindings, expansion) =>
                assert(bindings.isEmpty)
                val old = sources
                sources = old.tail
                traverse(expansion)(inlineContext(EmptyTree).withSource(sources.head))
                sources = old
              case Inlined(call, bindings, expansion) =>
                bindings.foreach(traverse(_))
                sources = call.symbol.topLevelClass.source :: sources
                if (!isMacro(call)) // FIXME macro implementations can drop Inlined nodes. We should reinsert them after macro expansion based on the positions of the trees
                  traverse(expansion)(inlineContext(call).withSource(sources.head))
                sources = sources.tail
              case _ => traverseChildren(tree)
            }
          }
        }.traverse(tree)
      case _ =>
    }
  }

  private def isMacro(call: Tree)(implicit ctx: Context) = {
    if (ctx.phase <= ctx.postTyperPhase) call.symbol.is(Macro)
    else call.isInstanceOf[Select] // The call of a macro after typer is encoded as a Select while other inlines are Ident
                                   // TODO remove this distinction once Inline nodes of expanded macros can be trusted (also in Inliner.inlineCallTrace)
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy