Skip to content

Commit 9ba7cf8

Browse files
committed
fixes incorrect handling of Annotated in lazy copier
1 parent 0acb8a3 commit 9ba7cf8

File tree

5 files changed

+60
-1
lines changed

5 files changed

+60
-1
lines changed

src/reflect/scala/reflect/internal/Trees.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -811,7 +811,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
811811
}
812812
def Annotated(tree: Tree, annot: Tree, arg: Tree) = tree match {
813813
case t @ Annotated(annot0, arg0)
814-
if (annot0==annot) => t
814+
if (annot0==annot && arg0==arg) => t
815815
case _ => treeCopy.Annotated(tree, annot, arg)
816816
}
817817
def SingletonTypeTree(tree: Tree, ref: Tree) = tree match {

test/files/pos/annotated-treecopy.check

Whitespace-only changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-language:experimental.macros
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import scala.language.experimental.macros
2+
import scala.reflect.macros.Context
3+
import collection.mutable.ListBuffer
4+
import collection.mutable.Stack
5+
6+
object Macros {
7+
trait TypedFunction {
8+
def tree: scala.reflect.runtime.universe.Tree
9+
val typeIn: String
10+
val typeOut: String
11+
}
12+
13+
def tree[T,U](f:Function1[T,U]): Function1[T,U] = macro tree_impl[T,U]
14+
15+
def tree_impl[T:c.WeakTypeTag,U:c.WeakTypeTag](c: Context)
16+
(f:c.Expr[Function1[T,U]]): c.Expr[Function1[T,U]] = {
17+
import c.universe._
18+
val ttag = c.weakTypeTag[U]
19+
f match {
20+
case Expr(Function(List(ValDef(_,n,tp,_)),b)) =>
21+
// normalize argument name
22+
var b1 = new Transformer {
23+
override def transform(tree: Tree): Tree = tree match {
24+
case Ident(x) if (x==n) => Ident(newTermName("_arg"))
25+
case tt @ TypeTree() if tt.original != null => TypeTree(tt.tpe) setOriginal transform(tt.original)
26+
// without the fix to LazyTreeCopier.Annotated, we would need to uncomment the line below to make the macro work
27+
// that's because the pattern match in the input expression gets expanded into Typed(<x>, TypeTree(<Int @unchecked>))
28+
// with the original of the TypeTree being Annotated(<@unchecked>, Ident(<x>))
29+
// then the macro tries to replace all Ident(<x>) trees with Ident(<_arg>), recurs into the original of the TypeTree, changes it,
30+
// but leaves the <@unchecked> part untouched. this signals the misguided LazyTreeCopier that the Annotated tree hasn't been modified,
31+
// so the original tree should be copied over and returned => crash when later <x: @unchecked> re-emerges from TypeTree.original
32+
// case Annotated(annot, arg) => treeCopy.Annotated(tree, transform(annot).duplicate, transform(arg))
33+
case _ => super.transform(tree)
34+
}
35+
}.transform(b)
36+
37+
val reifiedTree = c.reifyTree(treeBuild.mkRuntimeUniverseRef, EmptyTree, b1)
38+
val reifiedExpr = c.Expr[scala.reflect.runtime.universe.Expr[T => U]](reifiedTree)
39+
val template =
40+
c.universe.reify(new (T => U) with TypedFunction {
41+
override def toString = c.literal(tp+" => "+ttag.tpe+" { "+b1.toString+" } ").splice // DEBUG
42+
def tree = reifiedExpr.splice.tree
43+
val typeIn = c.literal(tp.toString).splice
44+
val typeOut = c.literal(ttag.tpe.toString).splice
45+
def apply(_arg: T): U = c.Expr[U](b1)(ttag.asInstanceOf[c.WeakTypeTag[U]]).splice
46+
})
47+
val untyped = c.resetLocalAttrs(template.tree)
48+
49+
c.Expr[T => U](untyped)
50+
case _ => sys.error("Bad function type")
51+
}
52+
}
53+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
object Test extends App {
2+
import Macros._
3+
// tree { (x:((Int,Int,Int),(Int,Int,Int))) => { val y=x; val ((r1,m1,c1),(r2,m2,c2))=y; (r1, m1 + m2 + r1 * c1 * c2, c2) } }
4+
tree { (x:((Int,Int,Int),(Int,Int,Int))) => { val ((r1,m1,c1),(r2,m2,c2))=x; (r1, m1 + m2 + r1 * c1 * c2, c2) } }
5+
}

0 commit comments

Comments
 (0)