Skip to content

Commit d6aa9e4

Browse files
committed
fix memberType for constructor params
1 parent 814528c commit d6aa9e4

File tree

3 files changed

+110
-1
lines changed

3 files changed

+110
-1
lines changed

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1926,7 +1926,19 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
19261926
else
19271927
member.info
19281928

1929-
memberInfo.asSeenFrom(self, member.owner) match
1929+
val memberInfoSubstituted =
1930+
if member.owner.isConstructor then
1931+
self match
1932+
case dotc.core.Types.AppliedType(_, args) =>
1933+
val ctorTypeParams = member.owner.paramSymss.flatten.filter(_.isType)
1934+
if ctorTypeParams.length == args.length then
1935+
memberInfo.subst(ctorTypeParams, args)
1936+
else
1937+
memberInfo
1938+
case _ => memberInfo
1939+
else memberInfo
1940+
1941+
memberInfoSubstituted.asSeenFrom(self, member.owner) match
19301942
case dotc.core.Types.ClassInfo(prefix, sym, _, _, _) =>
19311943
// We do not want to expose ClassInfo in the reflect API, instead we change it to a TypeRef,
19321944
// see issue #22395
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import scala.quoted.*
2+
3+
object Repro:
4+
inline def singletonValues[A]: List[A] = ${ singletonValuesImpl[A] }
5+
6+
private def singletonValuesImpl[A: Type](using Quotes): Expr[List[A]] =
7+
import quotes.reflect.*
8+
9+
def collectValues[T: Type]: List[Expr[T]] =
10+
val tpe = TypeRepr.of[T]
11+
tpe.dealias match
12+
case o: OrType => unionValues[T](o)
13+
case _ if tpe.isSingleton => singletonValue[T](tpe) :: Nil
14+
case _ =>
15+
val sym = tpe.typeSymbol
16+
if sym.flags.is(Flags.Sealed) then sumValues[T](sym)
17+
else if sym.flags.is(Flags.Case) && sym.caseFields.nonEmpty then productValues[T](tpe, sym)
18+
else
19+
report.errorAndAbort(
20+
s"Cannot derive values for ${tpe.show}. Supported types: singleton types, " +
21+
"enums, sealed traits/classes, union types, and case classes/tuples whose fields are all enumerable."
22+
)
23+
24+
def singletonValue[T: Type](tpe: TypeRepr): Expr[T] =
25+
tpe.asType match
26+
case '[t] =>
27+
Expr.summon[ValueOf[t]] match
28+
case Some(vo) => '{ $vo.value }.asExprOf[T]
29+
case None => report.errorAndAbort(s"Cannot determine value for singleton type: ${tpe.show}")
30+
31+
def unionValues[T: Type](orType: OrType): List[Expr[T]] =
32+
def extract(tpe: TypeRepr): List[Expr[T]] =
33+
tpe.dealias match
34+
case o: OrType => extract(o.left) ++ extract(o.right)
35+
case s if s.isSingleton => singletonValue[T](s) :: Nil
36+
case other => report.errorAndAbort(s"Unsupported type in union: ${other.show}.")
37+
extract(orType)
38+
39+
def sumValues[T: Type](sym: Symbol): List[Expr[T]] =
40+
sym.children.flatMap { child =>
41+
if child.isTerm then
42+
child.termRef.asType match
43+
case '[t] =>
44+
Expr.summon[ValueOf[t]] match
45+
case Some(vo) => '{ $vo.value }.asExprOf[T] :: Nil
46+
case None => report.errorAndAbort(s"Cannot get value for: ${child.name}")
47+
else
48+
child.typeRef.asType match
49+
case '[c] => collectValues[c].map(_.asExprOf[T])
50+
}
51+
52+
def productValues[T: Type](tpe: TypeRepr, sym: Symbol): List[Expr[T]] =
53+
val constructorParams = sym.primaryConstructor.paramSymss.flatten.filter(_.isTerm)
54+
val fieldTypes = constructorParams.map(f => tpe.memberType(f).widen.dealias)
55+
val fieldValueExprs: List[List[Term]] = fieldTypes.map { ft =>
56+
ft.asType match
57+
case '[f] => collectValues[f].map(_.asTerm)
58+
}
59+
val cartesian = fieldValueExprs.foldRight(List(List.empty[Term])) { (vals, acc) =>
60+
for v <- vals; rest <- acc yield v :: rest
61+
}
62+
cartesian.map { args =>
63+
val companion = Ref(sym.companionModule)
64+
val applyMethod = sym.companionModule.methodMember("apply").head
65+
val typeParams = applyMethod.paramSymss.flatten.filter(_.isTypeParam)
66+
if typeParams.nonEmpty then Select.overloaded(companion, "apply", fieldTypes, args).asExprOf[T]
67+
else Select.overloaded(companion, "apply", Nil, args).asExprOf[T]
68+
}
69+
70+
Expr.ofList(collectValues[A])
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
object TestCase1:
2+
enum Foo:
3+
case A
4+
case B
5+
enum Bar:
6+
case A
7+
case B
8+
9+
val values = Repro.singletonValues[(Foo, Bar)]
10+
11+
def TestCase2 =
12+
type Foo = "a" | "b"
13+
type Bar = "x" | "y"
14+
15+
val values = Repro.singletonValues[(Foo, Bar)]
16+
17+
case class MyPair[A, B](first: A, second: B)
18+
19+
object TestCase3:
20+
enum X:
21+
case P
22+
case Q
23+
enum Y:
24+
case R
25+
case S
26+
27+
val values = Repro.singletonValues[MyPair[X, Y]]

0 commit comments

Comments
 (0)