Skip to content

Instantly share code, notes, and snippets.

@mandubian
Last active August 29, 2015 13:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mandubian/10878369 to your computer and use it in GitHub Desktop.
Save mandubian/10878369 to your computer and use it in GitHub Desktop.
Do you see why this slains the compiler?
import scala.reflect.macros.Context
import scala.reflect.api.Universe
object Foo {
def doit[T](t: T) = ???
def bar[T](body: T): Option[T] = macro barImpl[T]
def barImpl[T: c.WeakTypeTag](c: Context)(body: c.Expr[T]): c.Expr[Option[T]] = {
import c.universe._, c.internal._, decorators._, Flag._
def doitMethod(u: Universe)(macroSymbol: u.Symbol): u.Symbol = {
import u._
macroSymbol.owner.typeSignature.member(newTermName("doit"))
}
lazy val doitSymbol = doitMethod(c.universe)(c.macroApplication.symbol).ensuring(_ != NoSymbol)
val res = typingTransform(body.tree)((tree, api) => {
def defineVal(prefix: String, lhs: Tree, pos: Position): ValDef = {
val sym = api.currentOwner.newTermSymbol(c.freshName(prefix), pos, SYNTHETIC).setInfo(lhs.tpe)
lhs.changeOwner(api.currentOwner, sym)
valDef(sym, lhs.changeOwner(api.currentOwner, sym)).setType(NoType).setPos(pos)
}
def defineParam(prefix: String, pos: Position, tpe: Type): ValDef = {
val sym = api.currentOwner.newTermSymbol(c.freshName(prefix), pos, PARAM).setInfo(tpe)
valDef(sym).setType(tpe).setPos(pos)
}
tree match {
case q"$fun($t)" if(fun.symbol == doitSymbol) =>
/**
Foo.bar[Int](5) should generate this code:
{
<synthetic> val toto$macro$148: Some[Int] = scala.Some.apply[Int](5);
<synthetic> val toto$macro$151: Option[Int] = toto$macro$148.map[Int](((t$macro$149: Int) => {
<synthetic> val toto$macro$150: Int = {
scala.this.Predef.println("result:".+(t$macro$149));
t$macro$149
};
toto$macro$150
}));
toto$macro$151
}
*/
// GENERATES:
// <synthetic> val toto$macro$148: Some[Int] = scala.Some.apply[Int](5);
val code = api.typecheck(q"Some($t)")
val valDef = defineVal("toto", code, tree.pos)
val valDefRef = gen.mkAttributedRef(valDef.symbol).setType(code.tpe).setPos(tree.pos)
val tpe = implicitly[WeakTypeTag[T]].tpe
val param = defineParam("t", tree.pos, tpe)
val paramRef = gen.mkAttributedRef(param.symbol).setType(tpe).setPos(tree.pos)
// GENERATES:
// scala.this.Predef.println("result:".+(t$macro$149));
// toto$macro$149
//
val innerCode = api.typecheck(q"""
println("result:"+$paramRef)
$paramRef
""")
// GENERATES:
// <synthetic> val toto$macro$150: Int = {
// scala.this.Predef.println("result:".+(t$macro$149));
// toto$macro$149
// };
// toto$macro$150
val valInner = defineVal("toto", innerCode, tree.pos)
val valInnerRef = gen.mkAttributedRef(valInner.symbol).setType(innerCode.tpe).setPos(tree.pos)
val inner = Block(List(valInner), valInnerRef)
// GENERATES:
// <synthetic> val toto$macro$151: Option[Int] = toto$macro$148.map[Int](((t$macro$149: Int) => {
// <synthetic> val toto$macro$150: Int = {
// scala.this.Predef.println("result:".+(t$macro$149));
// t$macro$149
// };
// toto$macro$150
// }));
val code2 = api.typecheck(q"""
$valDefRef.map[$tpe]( ($param) => $inner )
""")
val valDef2 = defineVal("toto", code2, tree.pos)
val valDefRef2 = gen.mkAttributedRef(valDef2.symbol).setType(code.tpe).setPos(tree.pos)
// GENERATES:
// {
// <synthetic> val toto$macro$148: Some[Int] = scala.Some.apply[Int](5);
// <synthetic> val toto$macro$151: Option[Int] = toto$macro$148.map[Int](((t$macro$149: Int) => {
// <synthetic> val toto$macro$150: Int = {
// scala.this.Predef.println("result:".+(t$macro$149));
// t$macro$149
// };
// toto$macro$150
// }));
// toto$macro$151
// }
Block(List(valDef, valDef2), valDefRef2)
case e => e
}
})
println("CODE:"+res)
println("AST:"+showRaw(res, printTypes = true, /*printIds = true,*/ printKinds = true))
c.Expr[Option[T]](res)
}
}
scala> import Foo._
import Foo._
scala> Foo.bar[Int]{ doit(5) }
CODE:{
<synthetic> val toto$macro$161: Some[Int] = scala.Some.apply[Int](5);
<synthetic> val toto$macro$164: Option[Int] = toto$macro$161.map[Int](((t$macro$162: Int) => {
<synthetic> val toto$macro$163: Int = {
scala.this.Predef.println("result:".+(t$macro$162));
t$macro$162
};
toto$macro$163
}));
toto$macro$164
}
AST:Block(List(ValDef[23](Modifiers(SYNTHETIC), TermName("toto$macro$161")#VAL, TypeTree[41](), Apply[41](TypeApply[92](Select[29](Select[93](Ident[94](scala#PK), scala.Some#MOD), TermName("apply")#METH), List(TypeTree[10]())), List(Literal[95](Constant(5))))), ValDef[23](Modifiers(SYNTHETIC), TermName("toto$macro$164")#VAL, TypeTree[61](), Apply[61](TypeApply[96](Select[97](Ident[41](TermName("toto$macro$161")#VAL), TermName("map")#METH), List(TypeTree[10]())), List(Function[64](List(ValDef[23](Modifiers(PARAM), TermName("t$macro$162")#VAL, TypeTree[10](), EmptyTree)), Block[10](List(ValDef[23](Modifiers(SYNTHETIC), TermName("toto$macro$163")#VAL, TypeTree[10](), Block[10](List(Apply[77](Select[78](Select[98](This[80](TypeName("scala")), scala.Predef#MOD), TermName("println")#METH), List(Apply[81](Select[82](Literal[99](Constant("result:")), TermName("$plus")#METH), List(Ident[10](TermName("t$macro$162")#VAL)))))), Ident[10](TermName("t$macro$162")#VAL)))), Ident[10](TermName("toto$macro$163")#VAL))))))), Ident[41](TermName("toto$macro$164")#VAL))
[10] TypeRef(ThisType(scala#PKC), scala.Int#CLS, List())
[23] NoType
[29] PolyType(List(TypeName("A")#TPE), MethodType(List(TermName("x")#VAL), TypeRef(ThisType(scala#PKC), scala.Some#CLS, List(TypeRef(NoPrefix, TypeName("A")#TPE, List())))))
[41] TypeRef(ThisType(scala#PKC), scala.Some#CLS, List(TypeRef(ThisType(scala#PKC), scala.Int#CLS, List())))
[61] TypeRef(ThisType(scala#PKC), scala.Option#CLS, List(TypeRef(ThisType(scala#PKC), scala.Int#CLS, List())))
[64] TypeRef(ThisType(scala#PKC), scala.Function1#TRT, List(TypeRef(ThisType(scala#PKC), scala.Int#CLS, List()), TypeRef(ThisType(scala#PKC), scala.Int#CLS, List())))
[77] TypeRef(ThisType(scala#PKC), scala.Unit#CLS, List())
[78] MethodType(List(TermName("x")#VAL), TypeRef(ThisType(scala#PKC), scala.Unit#CLS, List()))
[80] ThisType(scala#PKC)
[81] TypeRef(ThisType(java.lang#PKC), java.lang.String#CLS, List())
[82] MethodType(List(TermName("x$1")#VAL), TypeRef(ThisType(java.lang#PKC), java.lang.String#CLS, List()))
[92] MethodType(List(TermName("x")#VAL), TypeRef(ThisType(scala#PKC), scala.Some#CLS, List(TypeRef(ThisType(scala#PKC), scala.Int#CLS, List()))))
[93] SingleType(SingleType(ThisType(<root>#PKC), scala#PK), scala.Some#MOD)
[94] SingleType(ThisType(<root>#PKC), scala#PK)
[95] ConstantType(Constant(5))
[96] MethodType(List(TermName("f")#VAL), TypeRef(ThisType(scala#PKC), scala.Option#CLS, List(TypeRef(ThisType(scala#PKC), scala.Int#CLS, List()))))
[97] PolyType(List(TypeName("B")#TPE), MethodType(List(TermName("f")#VAL), TypeRef(ThisType(scala#PKC), scala.Option#CLS, List(TypeRef(NoPrefix, TypeName("B")#TPE, List())))))
[98] SingleType(ThisType(scala#PKC), scala.Predef#MOD)
[99] ConstantType(Constant(result:))
java.lang.IllegalArgumentException: Could not find proxy for t$macro$162: Int in List(value t$macro$162, method apply$mcII$sp, <$anon: Function1>, value toto$macro$164, value res7, object $iw, object $iw, object $iw, object $iw, object $read, package $line179, package <root>) (currentOwner= value toto$macro$163 )
at scala.tools.nsc.transform.LambdaLift$LambdaLifter.scala$tools$nsc$transform$LambdaLift$LambdaLifter$$searchIn$1(LambdaLift.scala:317)
at scala.tools.nsc.transform.LambdaLift$LambdaLifter.scala$tools$nsc$transform$LambdaLift$LambdaLifter$$searchIn$1(LambdaLift.scala:322)
at scala.tools.nsc.transform.LambdaLift$LambdaLifter.scala$tools$nsc$transform$LambdaLift$LambdaLifter$$searchIn$1(LambdaLift.scala:322)
at scala.tools.nsc.transform.LambdaLift$LambdaLifter.scala$tools$nsc$transform$LambdaLift$LambdaLifter$$searchIn$1(LambdaLift.scala:322)
at scala.tools.nsc.transform.LambdaLift$LambdaLifter.scala$tools$nsc$transform$LambdaLift$LambdaLifter$$searchIn$1(LambdaLift.scala:322)
at scala.tools.nsc.transform.LambdaLift$LambdaLifter.scala$tools$nsc$transform$LambdaLift$LambdaLifter$$searchIn$1(LambdaLift.scala:322)
at scala.tools.nsc.transform.LambdaLift$LambdaLifter.scala$tools$nsc$transform$LambdaLift$LambdaLifter$$searchIn$1(LambdaLift.scala:322)
at scala.tools.nsc.transform.LambdaLift$LambdaLifter.scala$tools$nsc$transform$LambdaLift$LambdaLifter$$searchIn$1(LambdaLift.scala:322)
at scala.tools.nsc.transform.LambdaLift$LambdaLifter.scala$tools$nsc$transform$LambdaLift$LambdaLifter$$searchIn$1(LambdaLift.scala:322)
at scala.tools.nsc.transform.LambdaLift$LambdaLifter.scala$tools$nsc$transform$LambdaLift$LambdaLifter$$searchIn$1(LambdaLift.scala:322)
at scala.tools.nsc.transform.LambdaLift$LambdaLifter.scala$tools$nsc$transform$LambdaLift$LambdaLifter$$searchIn$1(LambdaLift.scala:322)
at scala.tools.nsc.transform.LambdaLift$LambdaLifter.proxy(LambdaLift.scala:331)
at scala.tools.nsc.transform.LambdaLift$LambdaLifter.scala$tools$nsc$transform$LambdaLift$LambdaLifter$$proxyRef(LambdaLift.scala:364)
at scala.tools.nsc.transform.LambdaLift$LambdaLifter.postTransform(LambdaLift.scala:503)
...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment