diff --git a/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala b/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala index 930306f1bd64..300bc222a065 100644 --- a/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala +++ b/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala @@ -2,6 +2,7 @@ package dotty.tools.dotc.quoted import dotty.tools.dotc import dotty.tools.dotc.ast.tpd +import dotty.tools.dotc.ast.tpd.TreeOps import dotty.tools.dotc.ast.untpd import dotty.tools.dotc.core.Annotations import dotty.tools.dotc.core.Contexts._ @@ -745,7 +746,9 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext: def unapply(tree: Block): Option[(List[ValDef], Term)] = tree match { case Block((ddef @ DefDef(_, _, params :: Nil, _, Some(body))) :: Nil, Closure(meth, _)) if ddef.symbol == meth.symbol => - Some((params, body)) + val cleanParams = params.map(_.changeOwner(meth.symbol,ctx.owner)) + val cleanBody = body.changeOwner(meth.symbol,ctx.owner) + Some((cleanParams, cleanBody)) case _ => None } end Lambda diff --git a/tests/pos-macros/i9894/Macro_1.scala b/tests/pos-macros/i9894/Macro_1.scala new file mode 100644 index 000000000000..751a2d4b4b16 --- /dev/null +++ b/tests/pos-macros/i9894/Macro_1.scala @@ -0,0 +1,67 @@ +package x + +import scala.quoted._ + +trait CB[T]: + def map[S](f: T=>S): CB[S] = ??? + +class MyArr[A]: + def map1[B](f: A=>B):MyArr[B] = ??? + def map1Out[B](f: A=> CB[B]): CB[MyArr[B]] = ??? + +def await[T](x:CB[T]):T = ??? + +object CBM: + def pure[T](t:T):CB[T] = ??? + +object X: + + inline def process[T](inline f:T) = ${ + processImpl[T]('f) + } + + def processImpl[T:Type](f:Expr[T])(using qctx: QuoteContext):Expr[CB[T]] = + import qctx.reflect._ + + def transform(term:Term):Term = + term match + case ap@Apply(TypeApply(Select(obj,"map1"),targs),args) => + val nArgs = args.map(x => shiftLambda(x)) + val nSelect = Select.unique(obj, "map1Out") + Apply(TypeApply(nSelect,targs),nArgs) + //Apply.copy(ap)(TypeApply(nSelect,targs),nArgs) + case Apply(TypeApply(Ident("await"),targs),args) => args.head + case Apply(x,y) => + Apply(x, y.map(transform)) + case Block(stats, last) => Block(stats, transform(last)) + case Inlined(x,List(),body) => transform(body) + case l@Literal(x) => + '{ CBM.pure(${term.seal}) }.unseal + case other => + throw RuntimeException(s"Not supported $other") + + def shiftLambda(term:Term): Term = + term match + case lt@Lambda(params, body) => + val paramTypes = params.map(_.tpt.tpe) + val paramNames = params.map(_.name) + val mt = MethodType(paramNames)(_ => paramTypes, _ => Type[CB].unseal.tpe.appliedTo(body.tpe.widen) ) + val r = Lambda(mt, args => changeArgs(params,args,transform(body)) ) + r + case _ => + throw RuntimeException("lambda expected") + + def changeArgs(oldArgs:List[Tree], newArgs:List[Tree], body:Term):Term = + val association: Map[Symbol, Term] = (oldArgs zip newArgs).foldLeft(Map.empty){ + case (m, (oldParam, newParam: Term)) => m.updated(oldParam.symbol, newParam) + case (m, (oldParam, newParam: Tree)) => throw RuntimeException("Term expected") + } + val changes = new TreeMap() { + override def transformTerm(tree:Term)(using Context): Term = + tree match + case ident@Ident(name) => association.getOrElse(ident.symbol, super.transformTerm(tree)) + case _ => super.transformTerm(tree) + } + changes.transformTerm(body) + + transform(f.unseal).seal.cast[CB[T]] diff --git a/tests/pos-macros/i9894/Test_2.scala b/tests/pos-macros/i9894/Test_2.scala new file mode 100644 index 000000000000..c9d3a17fcf49 --- /dev/null +++ b/tests/pos-macros/i9894/Test_2.scala @@ -0,0 +1,15 @@ +package x + + +object Main { + + def main(args:Array[String]):Unit = + val arr = new MyArr[Int]() + val r = X.process{ + arr.map1( zDebug => + await(CBM.pure(1).map(a => zDebug + a)) + ) + } + println("r") + +}