Skip to content

Commit

Permalink
fixes incorrect handling of Annotated in lazy copier
Browse files Browse the repository at this point in the history
  • Loading branch information
xeno-by committed Dec 13, 2012
1 parent 0acb8a3 commit 9ba7cf8
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/reflect/scala/reflect/internal/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -811,7 +811,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
}
def Annotated(tree: Tree, annot: Tree, arg: Tree) = tree match {
case t @ Annotated(annot0, arg0)
if (annot0==annot) => t
if (annot0==annot && arg0==arg) => t
case _ => treeCopy.Annotated(tree, annot, arg)
}
def SingletonTypeTree(tree: Tree, ref: Tree) = tree match {
Expand Down
Empty file.
1 change: 1 addition & 0 deletions test/files/pos/annotated-treecopy.flags
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-language:experimental.macros
53 changes: 53 additions & 0 deletions test/files/pos/annotated-treecopy/Impls_Macros_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import scala.language.experimental.macros
import scala.reflect.macros.Context
import collection.mutable.ListBuffer
import collection.mutable.Stack

object Macros {
trait TypedFunction {
def tree: scala.reflect.runtime.universe.Tree
val typeIn: String
val typeOut: String
}

def tree[T,U](f:Function1[T,U]): Function1[T,U] = macro tree_impl[T,U]

def tree_impl[T:c.WeakTypeTag,U:c.WeakTypeTag](c: Context)
(f:c.Expr[Function1[T,U]]): c.Expr[Function1[T,U]] = {
import c.universe._
val ttag = c.weakTypeTag[U]
f match {
case Expr(Function(List(ValDef(_,n,tp,_)),b)) =>
// normalize argument name
var b1 = new Transformer {
override def transform(tree: Tree): Tree = tree match {
case Ident(x) if (x==n) => Ident(newTermName("_arg"))
case tt @ TypeTree() if tt.original != null => TypeTree(tt.tpe) setOriginal transform(tt.original)
// without the fix to LazyTreeCopier.Annotated, we would need to uncomment the line below to make the macro work
// that's because the pattern match in the input expression gets expanded into Typed(<x>, TypeTree(<Int @unchecked>))
// with the original of the TypeTree being Annotated(<@unchecked>, Ident(<x>))
// then the macro tries to replace all Ident(<x>) trees with Ident(<_arg>), recurs into the original of the TypeTree, changes it,
// but leaves the <@unchecked> part untouched. this signals the misguided LazyTreeCopier that the Annotated tree hasn't been modified,
// so the original tree should be copied over and returned => crash when later <x: @unchecked> re-emerges from TypeTree.original
// case Annotated(annot, arg) => treeCopy.Annotated(tree, transform(annot).duplicate, transform(arg))
case _ => super.transform(tree)
}
}.transform(b)

val reifiedTree = c.reifyTree(treeBuild.mkRuntimeUniverseRef, EmptyTree, b1)
val reifiedExpr = c.Expr[scala.reflect.runtime.universe.Expr[T => U]](reifiedTree)
val template =
c.universe.reify(new (T => U) with TypedFunction {
override def toString = c.literal(tp+" => "+ttag.tpe+" { "+b1.toString+" } ").splice // DEBUG
def tree = reifiedExpr.splice.tree
val typeIn = c.literal(tp.toString).splice
val typeOut = c.literal(ttag.tpe.toString).splice
def apply(_arg: T): U = c.Expr[U](b1)(ttag.asInstanceOf[c.WeakTypeTag[U]]).splice
})
val untyped = c.resetLocalAttrs(template.tree)

c.Expr[T => U](untyped)
case _ => sys.error("Bad function type")
}
}
}
5 changes: 5 additions & 0 deletions test/files/pos/annotated-treecopy/Test_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
object Test extends App {
import Macros._
// 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) } }
tree { (x:((Int,Int,Int),(Int,Int,Int))) => { val ((r1,m1,c1),(r2,m2,c2))=x; (r1, m1 + m2 + r1 * c1 * c2, c2) } }
}

0 comments on commit 9ba7cf8

Please sign in to comment.