Skip to content

Commit

Permalink
Backport "Fix #19732: quotes.reflect.Ref incorrectly casting This t…
Browse files Browse the repository at this point in the history
…o `RefTree`" to LTS (#20990)

Backports #19930 to the LTS branch.

PR submitted by the release tooling.
[skip ci]
  • Loading branch information
WojciechMazur authored Jul 4, 2024
2 parents 999c1b7 + 2c6e57c commit 9c615de
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 1 deletion.
9 changes: 8 additions & 1 deletion compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,14 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
withDefaultPos(tpd.ref(tp).asInstanceOf[tpd.RefTree])
def apply(sym: Symbol): Ref =
assert(sym.isTerm)
withDefaultPos(tpd.ref(sym).asInstanceOf[tpd.RefTree])
val refTree = tpd.ref(sym) match
case t @ tpd.This(ident) => // not a RefTree, so we need to work around this - issue #19732
// ident in `This` can be a TypeIdent of sym, so we manually prepare the ref here,
// knowing that the owner is actually `This`.
val term = Select(This(sym.owner), sym)
term.asInstanceOf[tpd.RefTree]
case other => other.asInstanceOf[tpd.RefTree]
withDefaultPos(refTree)
end Ref

type Ident = tpd.Ident
Expand Down
1 change: 1 addition & 0 deletions tests/run-macros/i19732.check
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Map(b -> 23)
42 changes: 42 additions & 0 deletions tests/run-macros/i19732/Macro_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// package dummy

import scala.quoted.*

trait Defaults[A]:
def defaults: Map[String, Any]

object Defaults:
inline def derived[A <: Product]: Defaults[A] = ${ defaultsImpl[A] }

def defaultsImpl[A <: Product: Type](using Quotes): Expr[Defaults[A]] =
'{
new Defaults[A]:
def defaults: Map[String, Any] = ${ defaultParmasImpl[A] }
}

def defaultParmasImpl[T](using quotes: Quotes, tpe: Type[T]): Expr[Map[String, Any]] =
import quotes.reflect.*

TypeRepr.of[T].classSymbol match
case None => '{ Map.empty[String, Any] }
case Some(sym) =>
val comp = sym.companionClass
val mod = Ref(sym.companionModule)
val names =
for p <- sym.caseFields if p.flags.is(Flags.HasDefault)
yield p.name
val namesExpr: Expr[List[String]] =
Expr.ofList(names.map(Expr(_)))

val body = comp.tree.asInstanceOf[ClassDef].body
val idents: List[Ref] =
for
case deff @ DefDef(name, _, _, _) <- body
if name.startsWith("$lessinit$greater$default")
yield mod.select(deff.symbol)
val typeArgs = TypeRepr.of[T].typeArgs
val identsExpr: Expr[List[Any]] =
if typeArgs.isEmpty then Expr.ofList(idents.map(_.asExpr))
else Expr.ofList(idents.map(_.appliedToTypes(typeArgs).asExpr))

'{ $namesExpr.zip($identsExpr).toMap }
7 changes: 7 additions & 0 deletions tests/run-macros/i19732/Test_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class Outer:
case class Inner(a: String, b: Int = 23) derives Defaults

object Test:
def main(args: Array[String]): Unit =
val outer = Outer()
println(summon[Defaults[outer.Inner]].defaults)

0 comments on commit 9c615de

Please sign in to comment.