Last active
August 29, 2015 13:59
-
-
Save mandubian/10878369 to your computer and use it in GitHub Desktop.
Do you see why this slains the compiler?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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