diff --git a/community-build/community-projects/scalatest b/community-build/community-projects/scalatest index ca500725dd96..6f0e0b28e403 160000 --- a/community-build/community-projects/scalatest +++ b/community-build/community-projects/scalatest @@ -1 +1 @@ -Subproject commit ca500725dd96618b625bac33226e387d754a67c1 +Subproject commit 6f0e0b28e4039fb7fd01508da246fad26423dcd9 diff --git a/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala b/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala index 184e76d28e6f..6d820094c216 100644 --- a/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala +++ b/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala @@ -242,6 +242,16 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext, scala.intern tpd.cpy.ValDef(original)(name.toTermName, tpt, rhs.getOrElse(tpd.EmptyTree)) def unapply(vdef: ValDef): Option[(String, TypeTree, Option[Term])] = Some((vdef.name.toString, vdef.tpt, optional(vdef.rhs))) + + def let(name: String, rhs: Term)(body: Ident => Term): Term = + val vdef = tpd.SyntheticValDef(name.toTermName, rhs) + val ref = tpd.ref(vdef.symbol).asInstanceOf[Ident] + Block(List(vdef), body(ref)) + + def let(terms: List[Term])(body: List[Ident] => Term): Term = + val vdefs = terms.map(term => tpd.SyntheticValDef("x".toTermName, term)) + val refs = vdefs.map(vdef => tpd.ref(vdef.symbol).asInstanceOf[Ident]) + Block(vdefs, body(refs)) end ValDef object ValDefMethodsImpl extends ValDefMethods: diff --git a/library/src/scala/tasty/Reflection.scala b/library/src/scala/tasty/Reflection.scala index f19b89745bcc..f16ebe9c1e4f 100644 --- a/library/src/scala/tasty/Reflection.scala +++ b/library/src/scala/tasty/Reflection.scala @@ -311,6 +311,15 @@ trait Reflection { reflection => def apply(symbol: Symbol, rhs: Option[Term]): ValDef def copy(original: Tree)(name: String, tpt: TypeTree, rhs: Option[Term]): ValDef def unapply(vdef: ValDef): Option[(String, TypeTree, Option[Term])] + + /** Creates a block `{ val = ; }` */ + def let(name: String, rhs: Term)(body: Ident => Term): Term + + /** Creates a block `{ val x = ; }` */ + def let(rhs: Term)(body: Ident => Term): Term = let("x", rhs)(body) + + /** Creates a block `{ val x1 = ; ...; val xn = ; }` */ + def let(terms: List[Term])(body: List[Ident] => Term): Term } given ValDefMethods as ValDefMethods = ValDefMethodsImpl @@ -3603,22 +3612,4 @@ trait Reflection { reflection => end TreeMap - // TODO: extract from Reflection - - /** Bind the `rhs` to a `val` and use it in `body` */ - def let(rhs: Term)(body: Ident => Term): Term = { - val sym = Symbol.newVal(Symbol.currentOwner, "x", rhs.tpe.widen, Flags.EmptyFlags, Symbol.noSymbol) - Block(List(ValDef(sym, Some(rhs))), body(Ref(sym).asInstanceOf[Ident])) - } - - /** Bind the given `terms` to names and use them in the `body` */ - def lets(terms: List[Term])(body: List[Term] => Term): Term = { - def rec(xs: List[Term], acc: List[Term]): Term = xs match { - case Nil => body(acc) - case x :: xs => let(x) { (x: Term) => rec(xs, x :: acc) } - } - rec(terms, Nil) - } - - } diff --git a/tests/pos-macros/i6535/Macro_1.scala b/tests/pos-macros/i6535/Macro_1.scala index 1bd52cc9be98..f9f26b8fa226 100644 --- a/tests/pos-macros/i6535/Macro_1.scala +++ b/tests/pos-macros/i6535/Macro_1.scala @@ -7,6 +7,7 @@ object scalatest { def assertImpl(cond: Expr[Boolean])(using qctx: QuoteContext) : Expr[Unit] = { import qctx.reflect._ import util._ + import ValDef.let cond.unseal.underlyingArgument match { case t @ Apply(Select(lhs, op), rhs :: Nil) => diff --git a/tests/pos-macros/i8866/Macro_1.scala b/tests/pos-macros/i8866/Macro_1.scala index bb970232fe0d..b5ca9a080956 100644 --- a/tests/pos-macros/i8866/Macro_1.scala +++ b/tests/pos-macros/i8866/Macro_1.scala @@ -14,7 +14,7 @@ object Macro { def impl(using qctx: QuoteContext): Expr[Int] = { import qctx.reflect._ - let( + ValDef.let( Select.unique( '{ OtherMacro }.unseal, "apply" diff --git a/tests/pos-macros/i8866b/Macro_1.scala b/tests/pos-macros/i8866b/Macro_1.scala index 0f7c5a61bb72..a17b3d71a1c9 100644 --- a/tests/pos-macros/i8866b/Macro_1.scala +++ b/tests/pos-macros/i8866b/Macro_1.scala @@ -9,7 +9,7 @@ object Macro { def impl(using qctx: QuoteContext): Expr[Int] = { import qctx.reflect._ - let( + ValDef.let( Select.unique( '{ Other }.unseal, "apply" diff --git a/tests/run-macros/i6171/Macro_1.scala b/tests/run-macros/i6171/Macro_1.scala index 867f9543804b..bb369595816e 100644 --- a/tests/run-macros/i6171/Macro_1.scala +++ b/tests/run-macros/i6171/Macro_1.scala @@ -14,10 +14,10 @@ object scalatest { cond.unseal.underlyingArgument match { case t @ Apply(Select(lhs, op), rhs :: Nil) => - let(lhs) { left => - let(rhs) { right => + ValDef.let(lhs) { left => + ValDef.let(rhs) { right => val app = Select.overloaded(left, op, Nil, right :: Nil) - let(app) { result => + ValDef.let(app) { result => val l = left.seal val r = right.seal val b = result.seal.cast[Boolean] @@ -28,10 +28,10 @@ object scalatest { }.seal.cast[Unit] case Apply(f @ Apply(Select(Apply(qual, lhs :: Nil), op), rhs :: Nil), implicits) if isImplicitMethodType(f.tpe) => - let(lhs) { left => - let(rhs) { right => + ValDef.let(lhs) { left => + ValDef.let(rhs) { right => val app = Select.overloaded(Apply(qual, left :: Nil), op, Nil, right :: Nil) - let(Apply(app, implicits)) { result => + ValDef.let(Apply(app, implicits)) { result => val l = left.seal val r = right.seal val b = result.seal.cast[Boolean] diff --git a/tests/run-macros/reflect-dsl/assert_1.scala b/tests/run-macros/reflect-dsl/assert_1.scala index a6fc8a23a5e8..14f9a9416fe4 100644 --- a/tests/run-macros/reflect-dsl/assert_1.scala +++ b/tests/run-macros/reflect-dsl/assert_1.scala @@ -14,10 +14,10 @@ object scalatest { cond.unseal.underlyingArgument match { case t @ Apply(sel @ Select(lhs, op), rhs :: Nil) => - let(lhs) { left => - let(rhs) { right => + ValDef.let(lhs) { left => + ValDef.let(rhs) { right => val app = left.select(sel.symbol).appliedTo(right) - let(app) { result => + ValDef.let(app) { result => val l = left.seal val r = right.seal val b = result.seal.cast[Boolean] @@ -28,10 +28,10 @@ object scalatest { }.seal.cast[Unit] case Apply(f @ Apply(sel @ Select(Apply(qual, lhs :: Nil), op), rhs :: Nil), implicits) if isImplicitMethodType(f.tpe) => - let(lhs) { left => - let(rhs) { right => + ValDef.let(lhs) { left => + ValDef.let(rhs) { right => val app = qual.appliedTo(left).select(sel.symbol).appliedTo(right) - let(Apply(app, implicits)) { result => + ValDef.let(Apply(app, implicits)) { result => val l = left.seal val r = right.seal val b = result.seal.cast[Boolean] diff --git a/tests/run-macros/reflect-pos-fun/assert_1.scala b/tests/run-macros/reflect-pos-fun/assert_1.scala index db4834ff4dab..fa4429a64ad7 100644 --- a/tests/run-macros/reflect-pos-fun/assert_1.scala +++ b/tests/run-macros/reflect-pos-fun/assert_1.scala @@ -10,8 +10,8 @@ object scalatest { cond.unseal.underlyingArgument match { case t @ Apply(TypeApply(Select(lhs, op), targs), rhs) => - let(lhs) { left => - lets(rhs) { rs => + ValDef.let(lhs) { left => + ValDef.let(rhs) { rs => val app = Select.overloaded(left, op, targs.map(_.tpe), rs) val b = app.seal.cast[Boolean] '{ scala.Predef.assert($b) }.unseal diff --git a/tests/run-macros/reflect-select-constructor/assert_1.scala b/tests/run-macros/reflect-select-constructor/assert_1.scala index ed14a7609283..1b1357be995c 100644 --- a/tests/run-macros/reflect-select-constructor/assert_1.scala +++ b/tests/run-macros/reflect-select-constructor/assert_1.scala @@ -14,10 +14,10 @@ object scalatest { cond.unseal.underlyingArgument match { case t @ Apply(Select(lhs, op), rhs :: Nil) => - let(lhs) { left => - let(rhs) { right => + ValDef.let(lhs) { left => + ValDef.let(rhs) { right => val app = Select.overloaded(left, op, Nil, right :: Nil) - let(app) { result => + ValDef.let(app) { result => val l = left.seal val r = right.seal val b = result.seal.cast[Boolean] @@ -28,10 +28,10 @@ object scalatest { }.seal.cast[Unit] case Apply(f @ Apply(Select(Apply(qual, lhs :: Nil), op), rhs :: Nil), implicits) if isImplicitMethodType(f.tpe) => - let(lhs) { left => - let(rhs) { right => + ValDef.let(lhs) { left => + ValDef.let(rhs) { right => val app = Select.overloaded(Apply(qual, left :: Nil), op, Nil, right :: Nil) - let(Apply(app, implicits)) { result => + ValDef.let(Apply(app, implicits)) { result => val l = left.seal val r = right.seal val b = result.seal.cast[Boolean] diff --git a/tests/run-macros/reflect-select-copy-2/assert_1.scala b/tests/run-macros/reflect-select-copy-2/assert_1.scala index f664d031fb86..9eb87ee044e3 100644 --- a/tests/run-macros/reflect-select-copy-2/assert_1.scala +++ b/tests/run-macros/reflect-select-copy-2/assert_1.scala @@ -14,9 +14,9 @@ object scalatest { cond.unseal.underlyingArgument match { case Apply(sel @ Select(lhs, op), rhs :: Nil) => - let(lhs) { left => - let(rhs) { right => - let(Apply(Select.copy(sel)(left, op), right :: Nil)) { result => + ValDef.let(lhs) { left => + ValDef.let(rhs) { right => + ValDef.let(Apply(Select.copy(sel)(left, op), right :: Nil)) { result => val l = left.seal val r = right.seal val b = result.seal.cast[Boolean] @@ -27,9 +27,9 @@ object scalatest { }.seal.cast[Unit] case Apply(f @ Apply(sel @ Select(Apply(qual, lhs :: Nil), op), rhs :: Nil), implicits) if isImplicitMethodType(f.tpe) => - let(lhs) { left => - let(rhs) { right => - let(Apply(Apply(Select.copy(sel)(Apply(qual, left :: Nil), op), right :: Nil), implicits)) { result => + ValDef.let(lhs) { left => + ValDef.let(rhs) { right => + ValDef.let(Apply(Apply(Select.copy(sel)(Apply(qual, left :: Nil), op), right :: Nil), implicits)) { result => val l = left.seal val r = right.seal val b = result.seal.cast[Boolean] diff --git a/tests/run-macros/reflect-select-symbol-constructor/assert_1.scala b/tests/run-macros/reflect-select-symbol-constructor/assert_1.scala index 5b6d61510521..30662a1adfa6 100644 --- a/tests/run-macros/reflect-select-symbol-constructor/assert_1.scala +++ b/tests/run-macros/reflect-select-symbol-constructor/assert_1.scala @@ -14,10 +14,10 @@ object scalatest { cond.unseal.underlyingArgument match { case t @ Apply(sel @ Select(lhs, op), rhs :: Nil) => - let(lhs) { left => - let(rhs) { right => + ValDef.let(lhs) { left => + ValDef.let(rhs) { right => val app = Apply(Select(left, sel.symbol), right :: Nil) - let(app) { result => + ValDef.let(app) { result => val l = left.seal val r = right.seal val b = result.seal.cast[Boolean] @@ -28,10 +28,10 @@ object scalatest { }.seal.cast[Unit] case Apply(f @ Apply(sel @ Select(Apply(qual, lhs :: Nil), op), rhs :: Nil), implicits) if isImplicitMethodType(f.tpe) => - let(lhs) { left => - let(rhs) { right => + ValDef.let(lhs) { left => + ValDef.let(rhs) { right => val app = Apply(Select(Apply(qual, left :: Nil), sel.symbol), right :: Nil) - let(Apply(app, implicits)) { result => + ValDef.let(Apply(app, implicits)) { result => val l = left.seal val r = right.seal val b = result.seal.cast[Boolean] diff --git a/tests/run-macros/reflect-select-value-class/assert_1.scala b/tests/run-macros/reflect-select-value-class/assert_1.scala index 8233d59efbdb..fda7233a5c27 100644 --- a/tests/run-macros/reflect-select-value-class/assert_1.scala +++ b/tests/run-macros/reflect-select-value-class/assert_1.scala @@ -14,10 +14,10 @@ object scalatest { cond.unseal.underlyingArgument match { case t @ Apply(Select(lhs, op), rhs :: Nil) => - let(lhs) { left => - let(rhs) { right => + ValDef.let(lhs) { left => + ValDef.let(rhs) { right => val app = Select.overloaded(left, op, Nil, right :: Nil) - let(app) { result => + ValDef.let(app) { result => val l = left.seal val r = right.seal val b = result.seal.cast[Boolean] @@ -28,10 +28,10 @@ object scalatest { }.seal.cast[Unit] case Apply(f @ Apply(Select(Apply(qual, lhs :: Nil), op), rhs :: Nil), implicits) if isImplicitMethodType(f.tpe) => - let(lhs) { left => - let(rhs) { right => + ValDef.let(lhs) { left => + ValDef.let(rhs) { right => val app = Select.overloaded(Apply(qual, left :: Nil), op, Nil, right :: Nil) - let(Apply(app, implicits)) { result => + ValDef.let(Apply(app, implicits)) { result => val l = left.seal val r = right.seal val b = result.seal.cast[Boolean] diff --git a/tests/run-macros/tasty-unsafe-let/quoted_1.scala b/tests/run-macros/tasty-unsafe-let/quoted_1.scala index 0958ae7dcf82..ff67f440e956 100644 --- a/tests/run-macros/tasty-unsafe-let/quoted_1.scala +++ b/tests/run-macros/tasty-unsafe-let/quoted_1.scala @@ -10,8 +10,8 @@ object Macros { val rhsTerm = rhs.unseal - import qctx.reflect.{let => letTerm} - letTerm(rhsTerm) { rhsId => + import qctx.reflect._ + ValDef.let(rhsTerm) { rhsId => Expr.betaReduce('{$body(${rhsId.seal.asInstanceOf[Expr[T]]})}).unseal // Dangerous uncheked cast! }.seal.cast[Unit] } diff --git a/tests/run-staging/staged-streams_1.scala b/tests/run-staging/staged-streams_1.scala index d86ff0bdc6d6..48966daae6e3 100644 --- a/tests/run-staging/staged-streams_1.scala +++ b/tests/run-staging/staged-streams_1.scala @@ -1,6 +1,5 @@ import scala.quoted._ import scala.quoted.staging._ -import scala.quoted.util._ import language.experimental.namedTypeArguments /**