Skip to content

Commit

Permalink
Handle macros that have themselves as original tree
Browse files Browse the repository at this point in the history
It has been reported in #1237 that stack overflows may occur during the
extraction of used names (and later of dependencies between files). This
problem has been introduced by #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 #1237
  • Loading branch information
Martin Duhem committed Apr 7, 2014
1 parent 12a799c commit a80966e
Show file tree
Hide file tree
Showing 4 changed files with 13 additions and 2 deletions.
7 changes: 6 additions & 1 deletion compile/interface/src/main/scala/xsbt/Dependency.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 => ()
}
Expand Down
8 changes: 7 additions & 1 deletion compile/interface/src/main/scala/xsbt/ExtractUsedNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 => ()
Expand Down

0 comments on commit a80966e

Please sign in to comment.