Handle macros that have themselves as original tree

It has been reported in sbt/sbt#1237 that stack overflows may occur during the
extraction of used names (and later of dependencies between files). This
problem has been introduced by sbt/sbt#1163, which was about recording the
dependencies of macro arguments.

When a macro is expanded, the compiler attaches the tree before expansion to
the tree representing the expanded macro. As of Scala 2.11-RC3, some macros
have themselves attached as original tree, which caused the same macro to be
inspected over and over until a stack overflow.

This commit solves this problem by making sure that the original of a macro
expansion will be inspected if and only if it is different from the expanded
tree.

Fixes sbt/sbt#1237
This commit is contained in:
Martin Duhem 2014-04-07 11:33:47 +02:00
parent 12a799c929
commit a80966e394
4 changed files with 13 additions and 2 deletions

View File

@ -146,7 +146,12 @@ final class Dependency(val global: CallbackGlobal) extends LocateClassFile
deps.foreach(addDependency)
case Template(parents, self, body) =>
traverseTrees(body)
case MacroExpansionOf(original) =>
/*
* Some macros appear to contain themselves as original tree
* In this case, we don't need to inspect the original tree because
* we already inspected its expansion, which is equal.
*/
case MacroExpansionOf(original) if original != tree =>
this.traverse(original)
case other => ()
}

View File

@ -55,7 +55,13 @@ class ExtractUsedNames[GlobalType <: CallbackGlobal](val global: GlobalType) ext
}
def handleTreeNode(node: Tree): Unit = {
def handleMacroExpansion(original: Tree): Unit = original.foreach(handleTreeNode)
def handleMacroExpansion(original: Tree): Unit = {
// Some macros seem to have themselves registered as original tree.
// In this case, we only need to handle the children of the original tree,
// because we already handled the expanded tree.
if(original == node) original.children.foreach(handleTreeNode)
else original.foreach(handleTreeNode)
}
def handleClassicTreeNode(node: Tree): Unit = node match {
case _: DefTree | _: Template => ()