@@ -105,18 +105,6 @@ class TreeChecker extends Phase with SymTransformer {
105105 else if (ctx.phase.prev.isCheckable)
106106 check(ctx.base.allPhases.toIndexedSeq, ctx)
107107
108- private def previousPhases (phases : List [Phase ])(using Context ): List [Phase ] = phases match {
109- case (phase : MegaPhase ) :: phases1 =>
110- val subPhases = phase.miniPhases
111- val previousSubPhases = previousPhases(subPhases.toList)
112- if (previousSubPhases.length == subPhases.length) previousSubPhases ::: previousPhases(phases1)
113- else previousSubPhases
114- case phase :: phases1 if phase ne ctx.phase =>
115- phase :: previousPhases(phases1)
116- case _ =>
117- Nil
118- }
119-
120108 def check (phasesToRun : Seq [Phase ], ctx : Context ): Tree = {
121109 val fusedPhase = ctx.phase.prevMega(using ctx)
122110 report.echo(s " checking ${ctx.compilationUnit} after phase ${fusedPhase}" )(using ctx)
@@ -219,7 +207,7 @@ object TreeChecker {
219207 class Checker (phasesToCheck : Seq [Phase ]) extends ReTyper with Checking {
220208 import ast .tpd ._
221209
222- private val nowDefinedSyms = util.HashSet [Symbol ]()
210+ protected val nowDefinedSyms = util.HashSet [Symbol ]()
223211 private val patBoundSyms = util.HashSet [Symbol ]()
224212 private val everDefinedSyms = MutableSymbolMap [untpd.Tree ]()
225213
@@ -724,4 +712,52 @@ object TreeChecker {
724712
725713 override def simplify (tree : Tree , pt : Type , locked : TypeVars )(using Context ): tree.type = tree
726714 }
715+
716+ /** Tree checker that can be applied to a local tree. */
717+ class LocalChecker (phasesToCheck : Seq [Phase ]) extends Checker (phasesToCheck : Seq [Phase ]):
718+ override def assertDefined (tree : untpd.Tree )(using Context ): Unit =
719+ // Only check definitions nested in the local tree
720+ if nowDefinedSyms.contains(tree.symbol.maybeOwner) then
721+ super .assertDefined(tree)
722+
723+ def checkMacroGeneratedTree (original : tpd.Tree , expansion : tpd.Tree )(using Context ): Unit =
724+ if ctx.settings.XcheckMacros .value then
725+ val checkingCtx = ctx
726+ .fresh
727+ .addMode(Mode .ImplicitsEnabled )
728+ .setReporter(new ThrowingReporter (ctx.reporter))
729+ val phases = ctx.base.allPhases.toList
730+ val treeChecker = new LocalChecker (previousPhases(phases))
731+
732+ try treeChecker.typed(expansion)(using checkingCtx)
733+ catch
734+ case err : java.lang.AssertionError =>
735+ report.error(
736+ s """ Malformed tree was found while expanding macro with -Xcheck-macros.
737+ |The tree does not conform to the compiler's tree invariants.
738+ |
739+ |Macro was:
740+ | ${scala.quoted.runtime.impl.QuotesImpl .showDecompiledTree(original)}
741+ |
742+ |The macro returned:
743+ | ${scala.quoted.runtime.impl.QuotesImpl .showDecompiledTree(expansion)}
744+ |
745+ |Error:
746+ | ${err.getMessage}
747+ |
748+ | """ ,
749+ original
750+ )
751+
752+ private [TreeChecker ] def previousPhases (phases : List [Phase ])(using Context ): List [Phase ] = phases match {
753+ case (phase : MegaPhase ) :: phases1 =>
754+ val subPhases = phase.miniPhases
755+ val previousSubPhases = previousPhases(subPhases.toList)
756+ if (previousSubPhases.length == subPhases.length) previousSubPhases ::: previousPhases(phases1)
757+ else previousSubPhases
758+ case phase :: phases1 if phase ne ctx.phase =>
759+ phase :: previousPhases(phases1)
760+ case _ =>
761+ Nil
762+ }
727763}
0 commit comments