Skip to content

Commit ff044e0

Browse files
Merge pull request #12893 from dotty-staging/fix-reflect-members
Properly handle self-types in reflection member lookup
2 parents 0cbe42b + b335873 commit ff044e0

File tree

5 files changed

+64
-5
lines changed

5 files changed

+64
-5
lines changed

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

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2483,15 +2483,22 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
24832483

24842484
def declaredFields: List[Symbol] = self.unforcedDecls.filter(isField)
24852485

2486+
/** The prefix on which a member lookup should be performed. */
2487+
private def lookupPrefix: TypeRepr =
2488+
if self.isClass then
2489+
self.thisType // Needed to handle self-types (as in tests/run-macros/self)
2490+
else
2491+
self.namedType
2492+
24862493
def memberField(name: String): Symbol = fieldMember(name)
24872494
def fieldMember(name: String): Symbol =
2488-
appliedTypeRef(self).allMembers.iterator.map(_.symbol).find {
2495+
lookupPrefix.allMembers.iterator.map(_.symbol).find {
24892496
sym => isField(sym) && sym.name.toString == name
24902497
}.getOrElse(dotc.core.Symbols.NoSymbol)
24912498

24922499
def memberFields: List[Symbol] = fieldMembers
24932500
def fieldMembers: List[Symbol] =
2494-
appliedTypeRef(self).allMembers.iterator.map(_.symbol).collect {
2501+
lookupPrefix.allMembers.iterator.map(_.symbol).collect {
24952502
case sym if isField(sym) => sym.asTerm
24962503
}.toList
24972504

@@ -2507,13 +2514,13 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
25072514

25082515
def memberMethod(name: String): List[Symbol] = methodMember(name)
25092516
def methodMember(name: String): List[Symbol] =
2510-
appliedTypeRef(self).allMembers.iterator.map(_.symbol).collect {
2517+
lookupPrefix.allMembers.iterator.map(_.symbol).collect {
25112518
case sym if isMethod(sym) && sym.name.toString == name => sym.asTerm
25122519
}.toList
25132520

25142521
def memberMethods: List[Symbol] = methodMembers
25152522
def methodMembers: List[Symbol] =
2516-
appliedTypeRef(self).allMembers.iterator.map(_.symbol).collect {
2523+
lookupPrefix.allMembers.iterator.map(_.symbol).collect {
25172524
case sym if isMethod(sym) => sym.asTerm
25182525
}.toList
25192526

scaladoc/src/dotty/tools/scaladoc/tasty/SyntheticSupport.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,13 @@ object SyntheticsSupport:
7474
import dotty.tools.dotc
7575
given ctx: dotc.core.Contexts.Context = quotes.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx
7676
val sym = rsym.asInstanceOf[dotc.core.Symbols.Symbol]
77-
sym.typeRef.appliedTo(sym.typeParams.map(_.typeRef)).allMembers.iterator.map(_.symbol)
77+
// `lookupPrefix` is private in `QuotesImpl#SymbolMethods`
78+
val lookupPrefix =
79+
if sym.isClass then
80+
sym.thisType
81+
else
82+
sym.namedType
83+
lookupPrefix.allMembers.iterator.map(_.symbol)
7884
.collect {
7985
case sym if
8086
(!sym.is(dotc.core.Flags.ModuleVal) || sym.is(dotc.core.Flags.Given)) &&

tests/run-macros/self.check

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
ExprType(TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class <root>)),object scala),Int))
2+
MethodType(List(x), List(TypeRef(TermRef(TermRef(ThisType(TypeRef(NoPrefix,module class <root>)),object scala),Predef),String)), TypeRef(TypeRef(ThisType(TypeRef(ThisType(TypeRef(NoPrefix,module class <root>)),module class <empty>)),B),X))
3+
MethodType(List(x), List(TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class <root>)),object scala),Int)), TypeRef(TypeRef(ThisType(TypeRef(ThisType(TypeRef(NoPrefix,module class <root>)),module class <empty>)),B),X))

tests/run-macros/self/Macro_1.scala

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import scala.quoted.*
2+
3+
trait A {
4+
type X
5+
}
6+
trait B { self: A =>
7+
def foo(x: Int): X
8+
def foo(x: String): X
9+
}
10+
11+
object Obj {
12+
def foo: Int = 1
13+
}
14+
15+
object Macros {
16+
17+
inline def test(): String = ${ testImpl }
18+
19+
private def testImpl(using Quotes) : Expr[String] = {
20+
import quotes.reflect.*
21+
val bTpe = TypeRepr.of[B]
22+
val bSym = bTpe.classSymbol.get
23+
val bMethSyms = bSym.methodMember("foo") // Used to throw a MissingType exception
24+
val bMethTpes = bMethSyms.map(bTpe.memberType)
25+
26+
// Make sure we didn't break member lookup on terms
27+
val objTpe = TypeRepr.of[Obj.type]
28+
val objSym = objTpe.termSymbol
29+
val objMethSyms = objSym.methodMember("foo")
30+
val objMethTpes = objMethSyms.map(objTpe.memberType)
31+
32+
Expr((objMethTpes ++ bMethTpes).map(_.toString).sorted.mkString("\n"))
33+
}
34+
35+
}

tests/run-macros/self/Test_2.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
object Test {
3+
4+
def main(args: Array[String]): Unit = {
5+
println(Macros.test())
6+
}
7+
8+
}

0 commit comments

Comments
 (0)