summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2012-12-25 14:09:33 +0100
committerEugene Burmako <xeno.by@gmail.com>2012-12-25 14:09:33 +0100
commit48cdfefb95ee43ded08688d6c99a8c3a32d47f18 (patch)
tree8afef91284098f0e78e9995349b73db3dd716940
parentd2a7aa4ba1c048e52affb0eb2b9167a18dc29c83 (diff)
downloadscala-48cdfefb95ee43ded08688d6c99a8c3a32d47f18.tar.gz
scala-48cdfefb95ee43ded08688d6c99a8c3a32d47f18.tar.bz2
scala-48cdfefb95ee43ded08688d6c99a8c3a32d47f18.zip
macro expansions are now auto-duplicated
The fix still requires macro developers to be careful about sharing trees by references, because attributed DefTrees will still bring trouble. However this is an improvement, because it doesn't make matters worse and automatically fixes situations similar to one in the test. A much more thorough discussion with a number of open questions left: http://groups.google.com/group/scala-internals/browse_thread/thread/492560d941b315cc
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala8
-rw-r--r--src/reflect/scala/reflect/internal/Trees.scala7
-rw-r--r--test/files/run/macro-duplicate.check0
-rw-r--r--test/files/run/macro-duplicate.flags1
-rw-r--r--test/files/run/macro-duplicate/Impls_Macros_1.scala29
-rw-r--r--test/files/run/macro-duplicate/Test_2.scala6
6 files changed, 46 insertions, 5 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index 4d1ab98fa0..86c59bc671 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -691,9 +691,11 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
var expectedTpe = expandee.tpe
if (isNullaryInvocation(expandee)) expectedTpe = expectedTpe.finalResultType
- var typechecked = typecheck("macro def return type", expanded, expectedTpe)
- typechecked = typecheck("expected type", typechecked, pt)
- typechecked
+ // also see http://groups.google.com/group/scala-internals/browse_thread/thread/492560d941b315cc
+ val expanded0 = duplicateAndKeepPositions(expanded)
+ val expanded1 = typecheck("macro def return type", expanded0, expectedTpe)
+ val expanded2 = typecheck("expected type", expanded1, pt)
+ expanded2
} finally {
popMacroContext()
}
diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala
index 9e737528d2..ae9fca14cb 100644
--- a/src/reflect/scala/reflect/internal/Trees.scala
+++ b/src/reflect/scala/reflect/internal/Trees.scala
@@ -1499,15 +1499,18 @@ trait Trees extends api.Trees { self: SymbolTable =>
}
}
- private lazy val duplicator = new Transformer {
+ private lazy val duplicator = new Duplicator(focusPositions = true)
+ private class Duplicator(focusPositions: Boolean) extends Transformer {
override val treeCopy = newStrictTreeCopier
override def transform(t: Tree) = {
val t1 = super.transform(t)
- if ((t1 ne t) && t1.pos.isRange) t1 setPos t.pos.focus
+ if ((t1 ne t) && t1.pos.isRange && focusPositions) t1 setPos t.pos.focus
t1
}
}
+ def duplicateAndKeepPositions(tree: Tree) = new Duplicator(focusPositions = false) transform tree
+
// ------ copiers -------------------------------------------
def copyDefDef(tree: Tree)(
diff --git a/test/files/run/macro-duplicate.check b/test/files/run/macro-duplicate.check
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/files/run/macro-duplicate.check
diff --git a/test/files/run/macro-duplicate.flags b/test/files/run/macro-duplicate.flags
new file mode 100644
index 0000000000..cd66464f2f
--- /dev/null
+++ b/test/files/run/macro-duplicate.flags
@@ -0,0 +1 @@
+-language:experimental.macros \ No newline at end of file
diff --git a/test/files/run/macro-duplicate/Impls_Macros_1.scala b/test/files/run/macro-duplicate/Impls_Macros_1.scala
new file mode 100644
index 0000000000..de81923330
--- /dev/null
+++ b/test/files/run/macro-duplicate/Impls_Macros_1.scala
@@ -0,0 +1,29 @@
+import scala.reflect.macros.Context
+
+object Macros {
+ def impl(c: Context) = {
+ import c.universe._
+ val Expr(Block((cdef: ClassDef) :: Nil, _)) = reify { class C { def x = 2 } }
+ val cdef1 =
+ new Transformer {
+ override def transform(tree: Tree): Tree = tree match {
+ case Template(_, _, ctor :: defs) =>
+ val defs1 = defs collect {
+ case ddef @ DefDef(mods, name, tparams, vparamss, tpt, body) =>
+ val future = Select(Select(Select(Ident(newTermName("scala")), newTermName("concurrent")), newTermName("package")), newTermName("future"))
+ val Future = Select(Select(Ident(newTermName("scala")), newTermName("concurrent")), newTypeName("Future"))
+ val tpt1 = if (tpt.isEmpty) tpt else AppliedTypeTree(Future, List(tpt))
+ val body1 = Apply(future, List(body))
+ val name1 = newTermName("async" + name.toString.capitalize)
+ DefDef(mods, name1, tparams, vparamss, tpt1, body1)
+ }
+ Template(Nil, emptyValDef, ctor +: defs ::: defs1)
+ case _ =>
+ super.transform(tree)
+ }
+ } transform cdef
+ c.Expr[Unit](Block(cdef1 :: Nil, Literal(Constant(()))))
+ }
+
+ def foo = macro impl
+} \ No newline at end of file
diff --git a/test/files/run/macro-duplicate/Test_2.scala b/test/files/run/macro-duplicate/Test_2.scala
new file mode 100644
index 0000000000..6dbd4382d3
--- /dev/null
+++ b/test/files/run/macro-duplicate/Test_2.scala
@@ -0,0 +1,6 @@
+import scala.concurrent._
+import ExecutionContext.Implicits.global
+
+object Test extends App {
+ Macros.foo
+} \ No newline at end of file