Merge pull request #1238 from Duhemm/issue-1237

Handle macros that have themselves as original tree (Fix #1237)
This commit is contained in:
Grzegorz Kossakowski 2014-04-09 01:40:29 +02:00
commit 4d3133d8d7
14 changed files with 150 additions and 2 deletions

View File

@ -146,7 +146,13 @@ 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.
* See https://issues.scala-lang.org/browse/SI-8486
*/
case MacroExpansionOf(original) if original != tree =>
this.traverse(original)
case other => ()
}

View File

@ -55,7 +55,14 @@ 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.
// See https://issues.scala-lang.org/browse/SI-8486
if(original == node) original.children.foreach(handleTreeNode)
else original.foreach(handleTreeNode)
}
def handleClassicTreeNode(node: Tree): Unit = node match {
case _: DefTree | _: Template => ()

View File

@ -0,0 +1,5 @@
package macros
object Client {
Provider.printTree(Foo.str)
}

View File

@ -0,0 +1,5 @@
package macros
object Foo {
def str: String = "abc"
}

View File

@ -0,0 +1,3 @@
package macros
object Foo {
}

View File

@ -0,0 +1,12 @@
package macros
import scala.language.experimental.macros
import scala.reflect.macros._
object Provider {
def printTree(arg: Any) = macro printTreeImpl
def printTreeImpl(c: Context)(arg: c.Expr[Any]): c.Expr[String] = {
val argStr = arg.tree.toString
val literalStr = c.universe.Literal(c.universe.Constant(argStr))
c.Expr[String](literalStr)
}
}

View File

@ -0,0 +1,30 @@
import sbt._
import Keys._
object build extends Build {
val defaultSettings = Seq(
libraryDependencies <+= scalaVersion("org.scala-lang" % "scala-reflect" % _ ),
incOptions := incOptions.value.withNameHashing(true),
scalaVersion := "2.11.0-RC3"
)
lazy val root = Project(
base = file("."),
id = "macro",
aggregate = Seq(macroProvider, macroClient),
settings = Defaults.defaultSettings ++ defaultSettings
)
lazy val macroProvider = Project(
base = file("macro-provider"),
id = "macro-provider",
settings = Defaults.defaultSettings ++ defaultSettings
)
lazy val macroClient = Project(
base = file("macro-client"),
id = "macro-client",
dependencies = Seq(macroProvider),
settings = Defaults.defaultSettings ++ defaultSettings
)
}

View File

@ -0,0 +1,12 @@
> compile
# remove `Foo.str` which is an argument to a macro
$ copy-file macro-client/changes/Foo.scala macro-client/Foo.scala
# we should recompile Foo.scala first and then fail to compile Client.scala due to missing
# `Foo.str`
-> macro-client/compile
> clean
-> compile

View File

@ -0,0 +1,5 @@
package macros
object Client {
Provider.printTree(Provider.printTree(Foo.str))
}

View File

@ -0,0 +1,5 @@
package macros
object Foo {
def str: String = "abc"
}

View File

@ -0,0 +1,3 @@
package macros
object Foo {
}

View File

@ -0,0 +1,12 @@
package macros
import scala.language.experimental.macros
import scala.reflect.macros._
object Provider {
def printTree(arg: Any) = macro printTreeImpl
def printTreeImpl(c: Context)(arg: c.Expr[Any]): c.Expr[String] = {
val argStr = arg.tree.toString
val literalStr = c.universe.Literal(c.universe.Constant(argStr))
c.Expr[String](literalStr)
}
}

View File

@ -0,0 +1,30 @@
import sbt._
import Keys._
object build extends Build {
val defaultSettings = Seq(
libraryDependencies <+= scalaVersion("org.scala-lang" % "scala-reflect" % _ ),
incOptions := incOptions.value.withNameHashing(true),
scalaVersion := "2.11.0-RC3"
)
lazy val root = Project(
base = file("."),
id = "macro",
aggregate = Seq(macroProvider, macroClient),
settings = Defaults.defaultSettings ++ defaultSettings
)
lazy val macroProvider = Project(
base = file("macro-provider"),
id = "macro-provider",
settings = Defaults.defaultSettings ++ defaultSettings
)
lazy val macroClient = Project(
base = file("macro-client"),
id = "macro-client",
dependencies = Seq(macroProvider),
settings = Defaults.defaultSettings ++ defaultSettings
)
}

View File

@ -0,0 +1,13 @@
> compile
# remove `Foo.str` which is an argument to a macro
# (this macro itself that is an argument to another macro)
$ copy-file macro-client/changes/Foo.scala macro-client/Foo.scala
# we should recompile Foo.scala first and then fail to compile Client.scala due to missing
# `Foo.str`
-> macro-client/compile
> clean
-> compile