Skip to content

Commit

Permalink
Quotes reflect: Allow to return DefDef from a val symbol tree
Browse files Browse the repository at this point in the history
  • Loading branch information
jchyb committed Feb 14, 2025
1 parent 4518ce5 commit 4753d9a
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,14 @@ object FromSymbol {
case tpd.EmptyTree => tpd.DefDef(sym)
}

def valDefFromSym(sym: TermSymbol)(using Context): tpd.ValDef = sym.defTree match {
def valDefFromSym(sym: TermSymbol)(using Context): tpd.ValOrDefDef = sym.defTree match {
case tree: tpd.ValDef => tree
case tree: tpd.DefDef =>
// `Getters` phase replaces val class members with defs,
// so we may see a defdef here if we are running this on a symbol compiled
// in the same compilation (but before suspension, so that
// the symbol could have reached `Getters`).
tree
case tpd.EmptyTree => tpd.ValDef(sym)
}

Expand Down
3 changes: 2 additions & 1 deletion library/src/scala/quoted/Quotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4060,9 +4060,10 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
*
* If this symbol `isClassDef` it will return `a `ClassDef`,
* if this symbol `isTypeDef` it will return `a `TypeDef`,
* if this symbol `isValDef` it will return `a `ValDef`,
* if this symbol `isDefDef` it will return `a `DefDef`
* if this symbol `isBind` it will return `a `Bind`,
* if this symbol `isValDef` it will return `a `ValDef`,
* or a `DefDef` (as the compiler can replace val class members with defs during compilation),
* else will throw
*
* **Warning**: avoid using this method in macros.
Expand Down
30 changes: 30 additions & 0 deletions tests/pos-macros/i22584/Macro.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//> using options -Yretain-trees

import scala.quoted.*

object Macros {

inline def myMacro[A]: Unit = ${ myMacroImpl[A] }

private def myMacroImpl[A](using quotes: Quotes, tpe: Type[A]): Expr[Unit] = {
import quotes.reflect.*

val typeRepr = TypeRepr.of[A]
val typeSymbol = typeRepr.typeSymbol

val caseFieldSymbols: List[Symbol] = typeSymbol.fieldMembers
val caseFieldValOrDefDefs: List[ValDef | DefDef] =
caseFieldSymbols.sortBy(_.toString).map {
_.tree match {
case valDef: ValDef => valDef
case defDef: DefDef => defDef
case _ => report.errorAndAbort("???")
}
}

val expected = "List(DefDef(boolean,List(List()),TypeTree[TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Boolean)],Select(This(Ident(MyClass1)),boolean)), DefDef(finalVal,List(List()),TypeTree[TypeRef(ThisType(TypeRef(NoPrefix,module class lang)),class String)],Select(This(Ident(MyClass1)),finalVal)), DefDef(int,List(List()),TypeTree[TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Int)],Select(This(Ident(MyClass1)),int)), DefDef(string,List(List()),TypeTree[TypeRef(ThisType(TypeRef(NoPrefix,module class lang)),class String)],Select(This(Ident(MyClass1)),string)))"
assert(caseFieldValOrDefDefs.toString == expected)

'{ () }
}
}
4 changes: 4 additions & 0 deletions tests/pos-macros/i22584/Main.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import Types.*

@main def main() =
Macros.myMacro[MyClass1]
9 changes: 9 additions & 0 deletions tests/pos-macros/i22584/Types.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
object Types {
final case class MyClass1(
int: Int,
string: String,
boolean: Boolean,
) {
final val finalVal: String = "result"
}
}

0 comments on commit 4753d9a

Please sign in to comment.