Skip to content

Commit 4753d9a

Browse files
committed
Quotes reflect: Allow to return DefDef from a val symbol tree
1 parent 4518ce5 commit 4753d9a

File tree

5 files changed

+52
-2
lines changed

5 files changed

+52
-2
lines changed

compiler/src/dotty/tools/dotc/quoted/reflect/FromSymbol.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,14 @@ object FromSymbol {
4545
case tpd.EmptyTree => tpd.DefDef(sym)
4646
}
4747

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

library/src/scala/quoted/Quotes.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4060,9 +4060,10 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
40604060
*
40614061
* If this symbol `isClassDef` it will return `a `ClassDef`,
40624062
* if this symbol `isTypeDef` it will return `a `TypeDef`,
4063-
* if this symbol `isValDef` it will return `a `ValDef`,
40644063
* if this symbol `isDefDef` it will return `a `DefDef`
40654064
* if this symbol `isBind` it will return `a `Bind`,
4065+
* if this symbol `isValDef` it will return `a `ValDef`,
4066+
* or a `DefDef` (as the compiler can replace val class members with defs during compilation),
40664067
* else will throw
40674068
*
40684069
* **Warning**: avoid using this method in macros.

tests/pos-macros/i22584/Macro.scala

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//> using options -Yretain-trees
2+
3+
import scala.quoted.*
4+
5+
object Macros {
6+
7+
inline def myMacro[A]: Unit = ${ myMacroImpl[A] }
8+
9+
private def myMacroImpl[A](using quotes: Quotes, tpe: Type[A]): Expr[Unit] = {
10+
import quotes.reflect.*
11+
12+
val typeRepr = TypeRepr.of[A]
13+
val typeSymbol = typeRepr.typeSymbol
14+
15+
val caseFieldSymbols: List[Symbol] = typeSymbol.fieldMembers
16+
val caseFieldValOrDefDefs: List[ValDef | DefDef] =
17+
caseFieldSymbols.sortBy(_.toString).map {
18+
_.tree match {
19+
case valDef: ValDef => valDef
20+
case defDef: DefDef => defDef
21+
case _ => report.errorAndAbort("???")
22+
}
23+
}
24+
25+
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)))"
26+
assert(caseFieldValOrDefDefs.toString == expected)
27+
28+
'{ () }
29+
}
30+
}

tests/pos-macros/i22584/Main.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import Types.*
2+
3+
@main def main() =
4+
Macros.myMacro[MyClass1]

tests/pos-macros/i22584/Types.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
object Types {
2+
final case class MyClass1(
3+
int: Int,
4+
string: String,
5+
boolean: Boolean,
6+
) {
7+
final val finalVal: String = "result"
8+
}
9+
}

0 commit comments

Comments
 (0)