Skip to content

Commit fedc8f0

Browse files
Add basic structure for refined selectable macros
Co-authored-by: Nicolas Stucki <[email protected]>
1 parent 01dc942 commit fedc8f0

File tree

8 files changed

+104
-4
lines changed

8 files changed

+104
-4
lines changed

compiler/src/dotty/tools/dotc/tastyreflect/ReflectionCompilerInterface.scala

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,11 @@ class ReflectionCompilerInterface(val rootContext: core.Contexts.Context) extend
272272
case _ => term
273273
}
274274

275+
def TypeRef_apply(sym: Symbol)(given Context): TypeTree = {
276+
assert(sym.isType)
277+
withDefaultPos(tpd.ref(sym).asInstanceOf[tpd.TypeTree])
278+
}
279+
275280
type Ref = tpd.RefTree
276281

277282
def isInstanceOfRef(given ctx: Context): IsInstanceOf[Ref] = new {
@@ -281,8 +286,10 @@ class ReflectionCompilerInterface(val rootContext: core.Contexts.Context) extend
281286
case _ => None
282287
}
283288

284-
def Ref_apply(sym: Symbol)(given Context): Ref =
289+
def Ref_apply(sym: Symbol)(given Context): Ref = {
290+
assert(sym.isTerm)
285291
withDefaultPos(tpd.ref(sym).asInstanceOf[tpd.RefTree])
292+
}
286293

287294
type Ident = tpd.Ident
288295

compiler/src/dotty/tools/dotc/transform/Erasure.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ object Erasure {
523523
}
524524

525525
override def typedTypeApply(tree: untpd.TypeApply, pt: Type)(implicit ctx: Context): Tree = {
526-
val ntree = interceptTypeApply(tree.asInstanceOf[TypeApply])(ctx.withPhase(ctx.erasurePhase))
526+
val ntree = interceptTypeApply(tree.asInstanceOf[TypeApply])(ctx.withPhase(ctx.erasurePhase)).withSpan(tree.span)
527527

528528
ntree match {
529529
case TypeApply(fun, args) =>

library/src/scala/tasty/reflect/CompilerInterface.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,8 @@ trait CompilerInterface {
559559

560560
def Inferred_apply(tpe: Type)(given ctx: Context): Inferred
561561

562+
def TypeRef_apply(sym: Symbol)(given ctx: Context): TypeTree
563+
562564
/** Type tree representing a reference to definition with a given name */
563565
type TypeIdent <: TypeTree
564566

library/src/scala/tasty/reflect/ExtractorsPrinter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ class ExtractorsPrinter[R <: Reflection & Singleton](val tasty: R) extends Print
190190
case TypeRef(qual, name) =>
191191
this += "TypeRef(" += qual += ", \"" += name += "\")"
192192
case Refinement(parent, name, info) =>
193-
this += "Refinement(" += parent += ", " += name += ", " += info += ")"
193+
this += "Refinement(" += parent += ", \"" += name += "\", " += info += ")"
194194
case AppliedType(tycon, args) =>
195195
this += "AppliedType(" += tycon += ", " ++= args += ")"
196196
case AnnotatedType(underlying, annot) =>

library/src/scala/tasty/reflect/TreeOps.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -892,7 +892,8 @@ trait TreeOps extends Core {
892892
def unapply(x: TypeIdent): Some[TypeIdent] = Some(x)
893893

894894
object TypeIdent {
895-
// TODO def apply(name: String)(given ctx: Context): TypeIdent
895+
def apply(sym: Symbol)(given ctx: Context): TypeTree =
896+
internal.TypeRef_apply(sym)
896897
def copy(original: Tree)(name: String)(given ctx: Context): TypeIdent =
897898
internal.TypeIdent_copy(original)(name)
898899
def unapply(x: TypeIdent)(given ctx: Context): Option[String] = Some(x.name)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
((name,Emma),(age,42))
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import scala.quoted._
2+
3+
object Macro {
4+
5+
case class Record(elems: (String, Any)*) extends Selectable {
6+
def selectDynamic(name: String): Any = elems.find(_._1 == name).get._2
7+
}
8+
9+
inline def toHMap(s: Selectable) <: Tuple = ${ toHMapImpl('s)}
10+
11+
def toHMapImpl(s: Expr[Selectable])(given qctx:QuoteContext): Expr[Tuple] = {
12+
import qctx.tasty.{given, _}
13+
14+
val repr = s.unseal.tpe.widenTermRefExpr.dealias
15+
16+
def rec(tpe: Type): List[(String, Type)] = {
17+
tpe match {
18+
case Refinement(parent, name, info: Type) => (name, info) :: rec(parent)
19+
case _ => Nil
20+
}
21+
}
22+
23+
def tupleElem(name: String, info: Type): Expr[Any] = {
24+
val nameExpr = Expr(name)
25+
info.seal match {
26+
case '[$qType] =>
27+
Expr.ofTuple(Seq(nameExpr, '{$s.selectDynamic($nameExpr).asInstanceOf[$qType]}))
28+
}
29+
}
30+
31+
// val list = println(rec(repr))
32+
33+
val ret = rec(repr).reverse.map(e => tupleElem(e._1, e._2))
34+
35+
Expr.ofTuple(ret)
36+
}
37+
38+
inline def toSelectable[T](s: Tuple)<: T = ${ toSelectableImpl('s, '[T])}
39+
40+
def toSelectableImpl[T](s: Expr[Tuple], tpe: Type[T])(given qctx:QuoteContext): Expr[T] = {
41+
import qctx.tasty.{given, _}
42+
43+
val repr = s.unseal.tpe.widenTermRefExpr.dealias
44+
45+
println(repr.show)
46+
println(repr.showExtractors)
47+
48+
// new Record((res2._1._1, res2._1._2), (res2._2._1, res2._2._2)).asInstanceOf[Record {val name: String; val age: Int} ]
49+
50+
def rec(tpe: Type): List[(String, Type)] = {
51+
tpe match {
52+
// todo: check number based on prefix
53+
case AppliedType(_, args) => args.map{
54+
case AppliedType(_, ConstantType(Constant(name: String)) :: (info: Type) :: Nil) => (name, info)
55+
}
56+
}
57+
}
58+
val r = rec(repr)
59+
println(r)
60+
61+
println(tpe.unseal.symbol)
62+
println(TypeIdent(tpe.unseal.symbol))
63+
64+
println('{new Record()}.unseal.showExtractors)
65+
66+
'{ ??? }
67+
}
68+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import Macro._
2+
3+
object Test {
4+
5+
type Person = Record {
6+
val name: String
7+
val age: Int
8+
}
9+
10+
def main(args: Array[String]): Unit = {
11+
val person: Person = Record("name" -> "Emma", "age" -> 42).asInstanceOf[Person]
12+
13+
val res: (("name", String), ("age", Int)) = toHMap(person)
14+
15+
println(res)
16+
17+
val res2: Person = toSelectable[Record](res)
18+
19+
// new Record((res2._1._1, res2._1._2), (res2._2._1, res2._2._2)).asInstanceOf[Record {val name: String; val age: Int} ]
20+
}
21+
}

0 commit comments

Comments
 (0)