Skip to content

Commit 2685750

Browse files
authored
Try not to approximate prefixes when using memberType in reflect API (#22448)
To achieve this, we substitute This types in `member.info` referencing classSymbol with TypeReprs actual self (which may or may not be a This type) Fixes #22424
1 parent 8601228 commit 2685750

File tree

3 files changed

+39
-2
lines changed

3 files changed

+39
-2
lines changed

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

+10-2
Original file line numberDiff line numberDiff line change
@@ -1694,7 +1694,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
16941694
end SimpleSelectorTypeTest
16951695

16961696
object SimpleSelector extends SimpleSelectorModule:
1697-
def apply(name: String): SimpleSelector =
1697+
def apply(name: String): SimpleSelector =
16981698
withDefaultPos(untpd.ImportSelector(untpd.Ident(name.toTermName)))
16991699
def unapply(x: SimpleSelector): Some[String] = Some(x.name.toString)
17001700
end SimpleSelector
@@ -1837,7 +1837,15 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
18371837
def termSymbol: Symbol = self.termSymbol
18381838
def isSingleton: Boolean = self.isSingleton
18391839
def memberType(member: Symbol): TypeRepr =
1840-
member.info.asSeenFrom(self, member.owner)
1840+
// we replace thisTypes here to avoid resolving otherwise unstable prefixes into Nothing
1841+
val memberInfo =
1842+
if self.typeSymbol.isClassDef then
1843+
member.info.substThis(self.classSymbol.asClass, self)
1844+
else
1845+
member.info
1846+
memberInfo
1847+
.asSeenFrom(self, member.owner)
1848+
18411849
def baseClasses: List[Symbol] = self.baseClasses
18421850
def baseType(cls: Symbol): TypeRepr = self.baseType(cls)
18431851
def derivesFrom(cls: Symbol): Boolean = self.derivesFrom(cls)

tests/pos-macros/i22424/Macro_1.scala

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
import scala.quoted.*
3+
4+
object MockMaker:
5+
inline def inlineMock[T]: Unit = ${instance[T]}
6+
transparent inline def transparentInlineMock[T]: Unit = ${instance[T]}
7+
8+
def instance[T: Type](using quotes: Quotes): Expr[Unit] =
9+
import quotes.reflect._
10+
val tpe = TypeRepr.of[T]
11+
val symbol = tpe.typeSymbol.methodMember("innerTraitInOptions").head
12+
tpe.memberType(symbol) match
13+
case mt @ MethodType(_, args, _) =>
14+
assert(args.head.typeSymbol != TypeRepr.of[Nothing].typeSymbol, "argument is incorrectly approximated")
15+
val shownType = mt.show
16+
val expectedType = "(x: m.Embedded#ATrait[scala.Predef.String, scala.Int])m.Embedded#ATrait[scala.Predef.String, scala.Int]"
17+
assert(shownType == expectedType, s"Incorrect type shown. Obtained: $shownType, Expected: $expectedType")
18+
'{()}
19+
20+
trait PolymorphicTrait {
21+
trait Embedded {
22+
trait ATrait[A, B]
23+
def innerTraitInOptions(x: ATrait[String, Int]): ATrait[String, Int]
24+
}
25+
}

tests/pos-macros/i22424/Test_2.scala

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
@main def Test =
2+
val m = new PolymorphicTrait {}
3+
MockMaker.inlineMock[m.Embedded]
4+
MockMaker.transparentInlineMock[m.Embedded]

0 commit comments

Comments
 (0)