Skip to content

Commit

Permalink
Allow nested Quotes with a different owners
Browse files Browse the repository at this point in the history
This makes it possible to create `Expr`s with different owners to avoid
a call to `changeOwner`.
  • Loading branch information
nicolasstucki committed Oct 12, 2021
1 parent a771c86 commit 50d5fc3
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 0 deletions.
6 changes: 6 additions & 0 deletions compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2617,6 +2617,8 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler

def show(using printer: Printer[Symbol]): String = printer.show(self)

def asQuotes: Nested = new QuotesImpl(using ctx.withOwner(self))

end extension

private def appliedTypeRef(sym: Symbol): TypeRepr =
Expand Down Expand Up @@ -2907,6 +2909,10 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
|which has the AST representation
|${Printer.TreeStructure.show(tree)}
|
|
|
|Tip: The owner of a tree can be changed using method `Tree.changeOwner`.
|Tip: The default owner of definitions created in quotes can be changed using method `Symbol.asQuotes`.
|""".stripMargin)
case _ => traverseChildren(t)
}.traverse(tree)
Expand Down
21 changes: 21 additions & 0 deletions library/src/scala/quoted/Quotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3774,6 +3774,27 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>

/** Case class or case object children of a sealed trait or cases of an `enum`. */
def children: List[Symbol]

/** Returns a nested quote with this symbol as splice owner (`Symbol.spliceOwner`).
*
* Changes the owner under which the definition in a quote are created.
*
* Usage:
* ```scala
* new TreeMap:
* override def transformTerm(tree: Term)(owner: Symbol): Term =
* tree match
* case tree: Ident =>
* given Quotes = owner.asQuotes
* // Definitions contained in the quote will be owned by `owner`.
* // No need to use `changeOwner` in this case.
* '{ val x = ???; x }.asTerm
* ```
* @syntax markdown
*/
@experimental
def asQuotes: Nested

end extension
}

Expand Down
3 changes: 3 additions & 0 deletions project/MiMaFilters.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@ import com.typesafe.tools.mima.core.ProblemFilters._

object MiMaFilters {
val Library: Seq[ProblemFilter] = Seq(
// New APIs that will be introduced in 3.2.0
exclude[ReversedMissingMethodProblem]("scala.quoted.Quotes#reflectModule#SymbolMethods.asQuotes"),
exclude[DirectMissingMethodProblem]("scala.quoted.Quotes#reflectModule#SymbolMethods.asQuotes"),
)
}
20 changes: 20 additions & 0 deletions tests/pos-macros/i13571/Macro_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import scala.quoted.*

inline def checked2[A](inline n: A): A =
${ checkedImpl2[A]('{n}) }

private def checkedImpl2[A](n: Expr[A])(using Quotes, Type[A]): Expr[A] =
import quotes.reflect.*
val tree: Term = n.asTerm
val acc = new TreeMap:
override def transformTerm(tree: Term)(owner: Symbol): Term =
tree match
case Apply(Select(x, "*"), List(y)) =>
given Quotes = owner.asQuotes
'{
val xt = ${x.asExprOf[Long]}
xt
}.asTerm
case _ =>
super.transformTerm(tree)(owner)
acc.transformTerm(tree)(Symbol.spliceOwner).asExprOf[A]
6 changes: 6 additions & 0 deletions tests/pos-macros/i13571/Test_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
def test = {
val u = 3L
checked2(List(1L, 2L).map { k =>
u * 2L
})
}
22 changes: 22 additions & 0 deletions tests/pos-macros/i13571b/Macro_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import scala.quoted.*

inline def checked2[A](inline n: A): A =
${ checkedImpl2[A]('{n}) }

private def checkedImpl2[A](n: Expr[A])(using Quotes, Type[A]): Expr[A] =
import quotes.reflect.*
val tree: Term = n.asTerm
val acc = new TreeMap:
override def transformTerm(tree: Term)(owner: Symbol): Term =
tree match
case Apply(Select(x, "*"), List(y)) =>
bindLong(x.asExprOf[Long])(using owner.asQuotes).asTerm
case _ =>
super.transformTerm(tree)(owner)
acc.transformTerm(tree)(Symbol.spliceOwner).asExprOf[A]

def bindLong(expr: Expr[Long])(using Quotes): Expr[Long] =
'{
val xt = $expr
xt
}
6 changes: 6 additions & 0 deletions tests/pos-macros/i13571b/Test_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
def test = {
val u = 3L
checked2(List(1L, 2L).map { k =>
u * 2L
})
}

0 comments on commit 50d5fc3

Please sign in to comment.