Skip to content

Commit edaed8e

Browse files
authored
Merge pull request #110 from scala/backport-lts-3.3-21945
Backport "Fix scala#20471: owners of top-level symbols in cached quoted code being incorrect" to 3.3 LTS
2 parents 0606cb9 + def1144 commit edaed8e

File tree

3 files changed

+73
-1
lines changed

3 files changed

+73
-1
lines changed

Diff for: compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala

+3-1
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,9 @@ object PickledQuotes {
240240
treeOwner(tree) match
241241
case Some(owner) =>
242242
// Copy the cached tree to make sure the all definitions are unique.
243-
TreeTypeMap(oldOwners = List(owner), newOwners = List(owner)).apply(tree)
243+
val treeCpy = TreeTypeMap(oldOwners = List(owner), newOwners = List(owner)).apply(tree)
244+
// Then replace the symbol owner with the one pointed by the quote context.
245+
treeCpy.changeNonLocalOwners(ctx.owner)
244246
case _ =>
245247
tree
246248

Diff for: tests/pos-macros/i20471/Macro_1.scala

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import scala.annotation.experimental
2+
import scala.quoted.*
3+
import scala.annotation.tailrec
4+
5+
object FlatMap {
6+
@experimental inline def derived[F[_]]: FlatMap[F] = MacroFlatMap.derive
7+
}
8+
trait FlatMap[F[_]]{
9+
def tailRecM[A, B](a: A)(f: A => F[Either[A, B]]): F[B]
10+
}
11+
12+
@experimental
13+
object MacroFlatMap:
14+
15+
inline def derive[F[_]]: FlatMap[F] = ${ flatMap }
16+
17+
def flatMap[F[_]: Type](using Quotes): Expr[FlatMap[F]] = '{
18+
new FlatMap[F]:
19+
def tailRecM[A, B](a: A)(f: A => F[Either[A, B]]): F[B] =
20+
${ deriveTailRecM('{ a }, '{ f }) }
21+
}
22+
23+
def deriveTailRecM[F[_]: Type, A: Type, B: Type](
24+
a: Expr[A],
25+
f: Expr[A => F[Either[A, B]]]
26+
)(using q: Quotes): Expr[F[B]] =
27+
import quotes.reflect.*
28+
29+
val body: PartialFunction[(Symbol, TypeRepr), Term] = {
30+
case (method, tpe) => {
31+
given q2: Quotes = method.asQuotes
32+
'{
33+
def step(x: A): B = ???
34+
???
35+
}.asTerm
36+
}
37+
}
38+
39+
val term = '{ $f($a) }.asTerm
40+
val name = Symbol.freshName("$anon")
41+
val parents = List(TypeTree.of[Object], TypeTree.of[F[B]])
42+
43+
extension (sym: Symbol) def overridableMembers: List[Symbol] =
44+
val member1 = sym.methodMember("abstractEffect")(0)
45+
val member2 = sym.methodMember("concreteEffect")(0)
46+
def meth(member: Symbol) = Symbol.newMethod(sym, member.name, This(sym).tpe.memberType(member), Flags.Override, Symbol.noSymbol)
47+
List(meth(member1), meth(member2))
48+
49+
val cls = Symbol.newClass(Symbol.spliceOwner, name, parents.map(_.tpe), _.overridableMembers, None)
50+
51+
def transformDef(method: DefDef)(argss: List[List[Tree]]): Option[Term] =
52+
val sym = method.symbol
53+
Some(body.apply((sym, method.returnTpt.tpe)))
54+
55+
val members = cls.declarations
56+
.filterNot(_.isClassConstructor)
57+
.map: sym =>
58+
sym.tree match
59+
case method: DefDef => DefDef(sym, transformDef(method))
60+
case _ => report.errorAndAbort(s"Not supported: $sym in ${sym.owner}")
61+
62+
val newCls = New(TypeIdent(cls)).select(cls.primaryConstructor).appliedToNone
63+
Block(ClassDef(cls, parents, members) :: Nil, newCls).asExprOf[F[B]]

Diff for: tests/pos-macros/i20471/Main_2.scala

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import scala.annotation.experimental
2+
3+
@experimental
4+
object autoFlatMapTests:
5+
trait TestAlgebra[T] derives FlatMap:
6+
def abstractEffect(a: String): T
7+
def concreteEffect(a: String): T = abstractEffect(a + " concreteEffect")

0 commit comments

Comments
 (0)