@@ -42,10 +42,6 @@ class TreeChecker extends Phase with SymTransformer {
4242 private val seenClasses = collection.mutable.HashMap [String , Symbol ]()
4343 private val seenModuleVals = collection.mutable.HashMap [String , Symbol ]()
4444
45- def isValidJVMName (name : Name ): Boolean = name.toString.forall(isValidJVMChar)
46-
47- def isValidJVMMethodName (name : Name ): Boolean = name.toString.forall(isValidJVMMethodChar)
48-
4945 val NoSuperClassFlags : FlagSet = Trait | Package
5046
5147 def testDuplicate (sym : Symbol , registry : mutable.Map [String , Symbol ], typ : String )(using Context ): Unit = {
@@ -109,18 +105,6 @@ class TreeChecker extends Phase with SymTransformer {
109105 else if (ctx.phase.prev.isCheckable)
110106 check(ctx.base.allPhases.toIndexedSeq, ctx)
111107
112- private def previousPhases (phases : List [Phase ])(using Context ): List [Phase ] = phases match {
113- case (phase : MegaPhase ) :: phases1 =>
114- val subPhases = phase.miniPhases
115- val previousSubPhases = previousPhases(subPhases.toList)
116- if (previousSubPhases.length == subPhases.length) previousSubPhases ::: previousPhases(phases1)
117- else previousSubPhases
118- case phase :: phases1 if phase ne ctx.phase =>
119- phase :: previousPhases(phases1)
120- case _ =>
121- Nil
122- }
123-
124108 def check (phasesToRun : Seq [Phase ], ctx : Context ): Tree = {
125109 val fusedPhase = ctx.phase.prevMega(using ctx)
126110 report.echo(s " checking ${ctx.compilationUnit} after phase ${fusedPhase}" )(using ctx)
@@ -134,7 +118,6 @@ class TreeChecker extends Phase with SymTransformer {
134118
135119 val checkingCtx = ctx
136120 .fresh
137- .addMode(Mode .ImplicitsEnabled )
138121 .setReporter(new ThrowingReporter (ctx.reporter))
139122
140123 val checker = inContext(ctx) {
@@ -150,9 +133,80 @@ class TreeChecker extends Phase with SymTransformer {
150133 }
151134 }
152135
136+ /**
137+ * Checks that `New` nodes are always wrapped inside `Select` nodes.
138+ */
139+ def assertSelectWrapsNew (tree : Tree )(using Context ): Unit =
140+ (new TreeAccumulator [tpd.Tree ] {
141+ override def apply (parent : Tree , tree : Tree )(using Context ): Tree = {
142+ tree match {
143+ case tree : New if ! parent.isInstanceOf [tpd.Select ] =>
144+ assert(assertion = false , i " `New` node must be wrapped in a `Select`: \n parent = ${parent.show}\n child = ${tree.show}" )
145+ case _ : Annotated =>
146+ // Don't check inside annotations, since they're allowed to contain
147+ // somewhat invalid trees.
148+ case _ =>
149+ foldOver(tree, tree) // replace the parent when folding over the children
150+ }
151+ parent // return the old parent so that my siblings see it
152+ }
153+ })(tpd.EmptyTree , tree)
154+ }
155+
156+ object TreeChecker {
157+ /** - Check that TypeParamRefs and MethodParams refer to an enclosing type.
158+ * - Check that all type variables are instantiated.
159+ */
160+ def checkNoOrphans (tp0 : Type , tree : untpd.Tree = untpd.EmptyTree )(using Context ): Type = new TypeMap () {
161+ val definedBinders = new java.util.IdentityHashMap [Type , Any ]
162+ def apply (tp : Type ): Type = {
163+ tp match {
164+ case tp : BindingType =>
165+ definedBinders.put(tp, tp)
166+ mapOver(tp)
167+ definedBinders.remove(tp)
168+ case tp : ParamRef =>
169+ assert(definedBinders.get(tp.binder) != null , s " orphan param: ${tp.show}, hash of binder = ${System .identityHashCode(tp.binder)}, tree = ${tree.show}, type = $tp0" )
170+ case tp : TypeVar =>
171+ assert(tp.isInstantiated, s " Uninstantiated type variable: ${tp.show}, tree = ${tree.show}" )
172+ apply(tp.underlying)
173+ case _ =>
174+ mapOver(tp)
175+ }
176+ tp
177+ }
178+ }.apply(tp0)
179+
180+ /** Run some additional checks on the nodes of the trees. Specifically:
181+ *
182+ * - TypeTree can only appear in TypeApply args, New, Typed tpt, Closure
183+ * tpt, SeqLiteral elemtpt, ValDef tpt, DefDef tpt, and TypeDef rhs.
184+ */
185+ object TreeNodeChecker extends untpd.TreeTraverser :
186+ import untpd ._
187+ def traverse (tree : Tree )(using Context ) = tree match
188+ case t : TypeTree => assert(assertion = false , i " TypeTree not expected: $t" )
189+ case t @ TypeApply (fun, _targs) => traverse(fun)
190+ case t @ New (_tpt) =>
191+ case t @ Typed (expr, _tpt) => traverse(expr)
192+ case t @ Closure (env, meth, _tpt) => traverse(env); traverse(meth)
193+ case t @ SeqLiteral (elems, _elemtpt) => traverse(elems)
194+ case t @ ValDef (_, _tpt, _) => traverse(t.rhs)
195+ case t @ DefDef (_, paramss, _tpt, _) => for params <- paramss do traverse(params); traverse(t.rhs)
196+ case t @ TypeDef (_, _rhs) =>
197+ case t @ Template (constr, parents, self, _) => traverse(constr); traverse(parents); traverse(self); traverse(t.body)
198+ case t => traverseChildren(t)
199+ end traverse
200+
201+ private [TreeChecker ] def isValidJVMName (name : Name ): Boolean = name.toString.forall(isValidJVMChar)
202+
203+ private [TreeChecker ] def isValidJVMMethodName (name : Name ): Boolean = name.toString.forall(isValidJVMMethodChar)
204+
205+
153206 class Checker (phasesToCheck : Seq [Phase ]) extends ReTyper with Checking {
207+ import ast .tpd ._
154208
155- private val nowDefinedSyms = util.HashSet [Symbol ]()
209+ protected val nowDefinedSyms = util.HashSet [Symbol ]()
156210 private val patBoundSyms = util.HashSet [Symbol ]()
157211 private val everDefinedSyms = MutableSymbolMap [untpd.Tree ]()
158212
@@ -658,68 +712,50 @@ class TreeChecker extends Phase with SymTransformer {
658712 override def simplify (tree : Tree , pt : Type , locked : TypeVars )(using Context ): tree.type = tree
659713 }
660714
661- /**
662- * Checks that `New` nodes are always wrapped inside `Select` nodes.
663- */
664- def assertSelectWrapsNew (tree : Tree )(using Context ): Unit =
665- (new TreeAccumulator [tpd.Tree ] {
666- override def apply (parent : Tree , tree : Tree )(using Context ): Tree = {
667- tree match {
668- case tree : New if ! parent.isInstanceOf [tpd.Select ] =>
669- assert(assertion = false , i " `New` node must be wrapped in a `Select`: \n parent = ${parent.show}\n child = ${tree.show}" )
670- case _ : Annotated =>
671- // Don't check inside annotations, since they're allowed to contain
672- // somewhat invalid trees.
673- case _ =>
674- foldOver(tree, tree) // replace the parent when folding over the children
675- }
676- parent // return the old parent so that my siblings see it
677- }
678- })(tpd.EmptyTree , tree)
679- }
715+ /** Tree checker that can be applied to a local tree. */
716+ class LocalChecker (phasesToCheck : Seq [Phase ]) extends Checker (phasesToCheck : Seq [Phase ]):
717+ override def assertDefined (tree : untpd.Tree )(using Context ): Unit =
718+ // Only check definitions nested in the local tree
719+ if nowDefinedSyms.contains(tree.symbol.maybeOwner) then
720+ super .assertDefined(tree)
680721
681- object TreeChecker {
682- /** - Check that TypeParamRefs and MethodParams refer to an enclosing type.
683- * - Check that all type variables are instantiated.
684- */
685- def checkNoOrphans (tp0 : Type , tree : untpd.Tree = untpd.EmptyTree )(using Context ): Type = new TypeMap () {
686- val definedBinders = new java.util.IdentityHashMap [Type , Any ]
687- def apply (tp : Type ): Type = {
688- tp match {
689- case tp : BindingType =>
690- definedBinders.put(tp, tp)
691- mapOver(tp)
692- definedBinders.remove(tp)
693- case tp : ParamRef =>
694- assert(definedBinders.get(tp.binder) != null , s " orphan param: ${tp.show}, hash of binder = ${System .identityHashCode(tp.binder)}, tree = ${tree.show}, type = $tp0" )
695- case tp : TypeVar =>
696- assert(tp.isInstantiated, s " Uninstantiated type variable: ${tp.show}, tree = ${tree.show}" )
697- apply(tp.underlying)
698- case _ =>
699- mapOver(tp)
700- }
701- tp
702- }
703- }.apply(tp0)
722+ def checkMacroGeneratedTree (original : tpd.Tree , expansion : tpd.Tree )(using Context ): Unit =
723+ if ctx.settings.XcheckMacros .value then
724+ val checkingCtx = ctx
725+ .fresh
726+ .setReporter(new ThrowingReporter (ctx.reporter))
727+ val phases = ctx.base.allPhases.toList
728+ val treeChecker = new LocalChecker (previousPhases(phases))
729+
730+ try treeChecker.typed(expansion)(using checkingCtx)
731+ catch
732+ case err : java.lang.AssertionError =>
733+ report.error(
734+ s """ Malformed tree was found while expanding macro with -Xcheck-macros.
735+ |The tree does not conform to the compiler's tree invariants.
736+ |
737+ |Macro was:
738+ | ${scala.quoted.runtime.impl.QuotesImpl .showDecompiledTree(original)}
739+ |
740+ |The macro returned:
741+ | ${scala.quoted.runtime.impl.QuotesImpl .showDecompiledTree(expansion)}
742+ |
743+ |Error:
744+ | ${err.getMessage}
745+ |
746+ | """ ,
747+ original
748+ )
704749
705- /** Run some additional checks on the nodes of the trees. Specifically:
706- *
707- * - TypeTree can only appear in TypeApply args, New, Typed tpt, Closure
708- * tpt, SeqLiteral elemtpt, ValDef tpt, DefDef tpt, and TypeDef rhs.
709- */
710- object TreeNodeChecker extends untpd.TreeTraverser :
711- import untpd ._
712- def traverse (tree : Tree )(using Context ) = tree match
713- case t : TypeTree => assert(assertion = false , i " TypeTree not expected: $t" )
714- case t @ TypeApply (fun, _targs) => traverse(fun)
715- case t @ New (_tpt) =>
716- case t @ Typed (expr, _tpt) => traverse(expr)
717- case t @ Closure (env, meth, _tpt) => traverse(env); traverse(meth)
718- case t @ SeqLiteral (elems, _elemtpt) => traverse(elems)
719- case t @ ValDef (_, _tpt, _) => traverse(t.rhs)
720- case t @ DefDef (_, paramss, _tpt, _) => for params <- paramss do traverse(params); traverse(t.rhs)
721- case t @ TypeDef (_, _rhs) =>
722- case t @ Template (constr, parents, self, _) => traverse(constr); traverse(parents); traverse(self); traverse(t.body)
723- case t => traverseChildren(t)
724- end traverse
750+ private [TreeChecker ] def previousPhases (phases : List [Phase ])(using Context ): List [Phase ] = phases match {
751+ case (phase : MegaPhase ) :: phases1 =>
752+ val subPhases = phase.miniPhases
753+ val previousSubPhases = previousPhases(subPhases.toList)
754+ if (previousSubPhases.length == subPhases.length) previousSubPhases ::: previousPhases(phases1)
755+ else previousSubPhases
756+ case phase :: phases1 if phase ne ctx.phase =>
757+ phase :: previousPhases(phases1)
758+ case _ =>
759+ Nil
760+ }
725761}
0 commit comments