Skip to content

Commit 06339d9

Browse files
Merge pull request #6628 from dotty-staging/reflect-dsl
Add Dotty-style tree constructor DSL to reflect
2 parents 6b3b5be + 789471d commit 06339d9

File tree

3 files changed

+112
-0
lines changed

3 files changed

+112
-0
lines changed

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,43 @@ trait TreeOps extends Core {
179179
def pos(implicit ctx: Context): Position = kernel.Term_pos(self)
180180
def underlyingArgument(implicit ctx: Context): Term = kernel.Term_underlyingArgument(self)
181181
def underlying(implicit ctx: Context): Term = kernel.Term_underlying(self)
182+
183+
/** A unary apply node with given argument: `tree(arg)` */
184+
def appliedTo(arg: Term)(implicit ctx: Context): Term =
185+
appliedToArgs(arg :: Nil)
186+
187+
/** An apply node with given arguments: `tree(arg, args0, ..., argsN)` */
188+
def appliedTo(arg: Term, args: Term*)(implicit ctx: Context): Term =
189+
appliedToArgs(arg :: args.toList)
190+
191+
/** An apply node with given argument list `tree(args(0), ..., args(args.length - 1))` */
192+
def appliedToArgs(args: List[Term])(implicit ctx: Context): Apply =
193+
Apply(self, args)
194+
195+
/** The current tree applied to given argument lists:
196+
* `tree (argss(0)) ... (argss(argss.length -1))`
197+
*/
198+
def appliedToArgss(argss: List[List[Term]])(implicit ctx: Context): Term =
199+
((self: Term) /: argss)(Apply(_, _))
200+
201+
/** The current tree applied to (): `tree()` */
202+
def appliedToNone(implicit ctx: Context): Apply = appliedToArgs(Nil)
203+
204+
/** The current tree applied to given type argument: `tree[targ]` */
205+
def appliedToType(targ: Type)(implicit ctx: Context): Term =
206+
appliedToTypes(targ :: Nil)
207+
208+
/** The current tree applied to given type arguments: `tree[targ0, ..., targN]` */
209+
def appliedToTypes(targs: List[Type])(implicit ctx: Context): Term =
210+
appliedToTypeTrees(targs map (Inferred(_)))
211+
212+
/** The current tree applied to given type argument list: `tree[targs(0), ..., targs(targs.length - 1)]` */
213+
def appliedToTypeTrees(targs: List[TypeTree])(implicit ctx: Context): Term =
214+
if (targs.isEmpty) self else TypeApply(self, targs)
215+
216+
/** A select node that selects the given symbol.
217+
*/
218+
def select(sym: Symbol)(implicit ctx: Context): Select = Select(self, sym)
182219
}
183220

184221
object IsTerm {
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import scala.quoted._
2+
import scala.tasty._
3+
4+
object scalatest {
5+
6+
inline def assert(condition: => Boolean): Unit = ${ assertImpl('condition, '{""}) }
7+
8+
def assertImpl(cond: Expr[Boolean], clue: Expr[Any])(implicit refl: Reflection): Expr[Unit] = {
9+
import refl._
10+
import util._
11+
12+
def isImplicitMethodType(tp: Type): Boolean =
13+
Type.IsMethodType.unapply(tp).flatMap(tp => if tp.isImplicit then Some(true) else None).nonEmpty
14+
15+
cond.unseal.underlyingArgument match {
16+
case t @ Apply(sel @ Select(lhs, op), rhs :: Nil) =>
17+
let(lhs) { left =>
18+
let(rhs) { right =>
19+
val app = left.select(sel.symbol).appliedTo(right)
20+
let(app) { result =>
21+
val l = left.seal
22+
val r = right.seal
23+
val b = result.seal.cast[Boolean]
24+
val code = '{ scala.Predef.assert($b) }
25+
code.unseal
26+
}
27+
}
28+
}.seal.cast[Unit]
29+
case Apply(f @ Apply(sel @ Select(Apply(qual, lhs :: Nil), op), rhs :: Nil), implicits)
30+
if isImplicitMethodType(f.tpe) =>
31+
let(lhs) { left =>
32+
let(rhs) { right =>
33+
val app = qual.appliedTo(left).select(sel.symbol).appliedTo(right)
34+
let(Apply(app, implicits)) { result =>
35+
val l = left.seal
36+
val r = right.seal
37+
val b = result.seal.cast[Boolean]
38+
val code = '{ scala.Predef.assert($b) }
39+
code.unseal
40+
}
41+
}
42+
}.seal.cast[Unit]
43+
}
44+
}
45+
46+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
object Test {
2+
import scalatest._
3+
4+
case class Box[T](v: T) {
5+
def >(that: Box[T]): Boolean = this == that
6+
}
7+
8+
trait EqInt
9+
implicit val eq: EqInt = new EqInt {}
10+
11+
implicit class AnyOps[T](x: T) {
12+
def === (y: T)(implicit c: EqInt) = x == y
13+
}
14+
15+
def main(args: Array[String]): Unit = {
16+
val a = Box(Some(10))
17+
val five: Float = 5.0f
18+
val six: Double = 6.0
19+
val ten: Int = 10
20+
assert(a.v === Some(10))
21+
assert(five < six)
22+
assert(five > 4)
23+
assert(ten > 5)
24+
assert(six < 7)
25+
assert(six > 5L)
26+
assert(Box(6) > Box(6))
27+
assert(Box("h") > Box("h"))
28+
}
29+
}

0 commit comments

Comments
 (0)