Skip to content

Commit 9c615de

Browse files
Backport "Fix #19732: quotes.reflect.Ref incorrectly casting This to RefTree" to LTS (#20990)
Backports #19930 to the LTS branch. PR submitted by the release tooling. [skip ci]
2 parents 999c1b7 + 2c6e57c commit 9c615de

File tree

4 files changed

+58
-1
lines changed

4 files changed

+58
-1
lines changed

compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,14 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
449449
withDefaultPos(tpd.ref(tp).asInstanceOf[tpd.RefTree])
450450
def apply(sym: Symbol): Ref =
451451
assert(sym.isTerm)
452-
withDefaultPos(tpd.ref(sym).asInstanceOf[tpd.RefTree])
452+
val refTree = tpd.ref(sym) match
453+
case t @ tpd.This(ident) => // not a RefTree, so we need to work around this - issue #19732
454+
// ident in `This` can be a TypeIdent of sym, so we manually prepare the ref here,
455+
// knowing that the owner is actually `This`.
456+
val term = Select(This(sym.owner), sym)
457+
term.asInstanceOf[tpd.RefTree]
458+
case other => other.asInstanceOf[tpd.RefTree]
459+
withDefaultPos(refTree)
453460
end Ref
454461

455462
type Ident = tpd.Ident

tests/run-macros/i19732.check

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Map(b -> 23)

tests/run-macros/i19732/Macro_1.scala

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// package dummy
2+
3+
import scala.quoted.*
4+
5+
trait Defaults[A]:
6+
def defaults: Map[String, Any]
7+
8+
object Defaults:
9+
inline def derived[A <: Product]: Defaults[A] = ${ defaultsImpl[A] }
10+
11+
def defaultsImpl[A <: Product: Type](using Quotes): Expr[Defaults[A]] =
12+
'{
13+
new Defaults[A]:
14+
def defaults: Map[String, Any] = ${ defaultParmasImpl[A] }
15+
}
16+
17+
def defaultParmasImpl[T](using quotes: Quotes, tpe: Type[T]): Expr[Map[String, Any]] =
18+
import quotes.reflect.*
19+
20+
TypeRepr.of[T].classSymbol match
21+
case None => '{ Map.empty[String, Any] }
22+
case Some(sym) =>
23+
val comp = sym.companionClass
24+
val mod = Ref(sym.companionModule)
25+
val names =
26+
for p <- sym.caseFields if p.flags.is(Flags.HasDefault)
27+
yield p.name
28+
val namesExpr: Expr[List[String]] =
29+
Expr.ofList(names.map(Expr(_)))
30+
31+
val body = comp.tree.asInstanceOf[ClassDef].body
32+
val idents: List[Ref] =
33+
for
34+
case deff @ DefDef(name, _, _, _) <- body
35+
if name.startsWith("$lessinit$greater$default")
36+
yield mod.select(deff.symbol)
37+
val typeArgs = TypeRepr.of[T].typeArgs
38+
val identsExpr: Expr[List[Any]] =
39+
if typeArgs.isEmpty then Expr.ofList(idents.map(_.asExpr))
40+
else Expr.ofList(idents.map(_.appliedToTypes(typeArgs).asExpr))
41+
42+
'{ $namesExpr.zip($identsExpr).toMap }

tests/run-macros/i19732/Test_2.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class Outer:
2+
case class Inner(a: String, b: Int = 23) derives Defaults
3+
4+
object Test:
5+
def main(args: Array[String]): Unit =
6+
val outer = Outer()
7+
println(summon[Defaults[outer.Inner]].defaults)

0 commit comments

Comments
 (0)