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
+ }
0 commit comments