Skip to content

Factor out staging from the core of scala.quoted #7077

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/quoted/QuoteDriver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import dotty.tools.io.{AbstractFile, Directory, PlainDirectory, VirtualDirectory
import dotty.tools.repl.AbstractFileClassLoader
import dotty.tools.dotc.reporting._
import scala.quoted._
import scala.quoted.Toolbox
import scala.quoted.staging.Toolbox
import java.net.URLClassLoader

/** Driver to compile quoted code
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/quoted/ToolboxImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ object ToolboxImpl {
* @param settings toolbox settings
* @return A new instance of the toolbox
*/
def make(settings: scala.quoted.Toolbox.Settings, appClassloader: ClassLoader): scala.quoted.Toolbox = new scala.quoted.Toolbox {
def make(settings: scala.quoted.staging.Toolbox.Settings, appClassloader: ClassLoader): scala.quoted.staging.Toolbox = new scala.quoted.staging.Toolbox {

private[this] val driver: QuoteDriver = new QuoteDriver(appClassloader)

Expand All @@ -22,7 +22,7 @@ object ToolboxImpl {
def run[T](exprBuilder: QuoteContext => Expr[T]): T = synchronized {
try {
if (running) // detected nested run
throw new scala.quoted.Toolbox.RunScopeException()
throw new scala.quoted.staging.RunScopeException()
running = true
driver.run(exprBuilder, settings)
} finally {
Expand All @@ -35,7 +35,7 @@ object ToolboxImpl {

private[dotty] def checkScopeId(id: ScopeId) given Context: Unit = {
if (id != scopeId)
throw new Toolbox.RunScopeException
throw new scala.quoted.staging.RunScopeException
}

// TODO Explore more fine grained scope ids.
Expand Down
9 changes: 5 additions & 4 deletions compiler/test-resources/repl-macros/i6007
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
scala> import scala.quoted._
scala> implicit def toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make(getClass.getClassLoader)
def toolbox: quoted.Toolbox
scala> import scala.quoted.staging._
scala> implicit def toolbox: Toolbox = Toolbox.make(getClass.getClassLoader)
def toolbox: quoted.staging.Toolbox
scala> def v given QuoteContext = '{ (if true then Some(1) else None).map(v => v+1) }
def v given (x$1: quoted.QuoteContext): quoted.Expr[Option[Int]]
scala> scala.quoted.withQuoteContext(v.show)
scala> scala.quoted.staging.withQuoteContext(v.show)
val res0: String = (if (true) scala.Some.apply[scala.Int](1) else scala.None).map[scala.Int](((v: scala.Int) => v.+(1)))
scala> scala.quoted.run(v)
scala> scala.quoted.staging.run(v)
val res1: Option[Int] = Some(2)
5 changes: 3 additions & 2 deletions compiler/test-resources/repl-macros/i6263
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
scala> import quoted._
scala> implicit def toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make(getClass.getClassLoader)
def toolbox: quoted.Toolbox
scala> import quoted.staging._
scala> implicit def toolbox: Toolbox = Toolbox.make(getClass.getClassLoader)
def toolbox: quoted.staging.Toolbox
scala> def fn[T : Type](v : T) = println("ok")
def fn[T](v: T)(implicit evidence$1: quoted.Type[T]): Unit
scala> withQuoteContext { fn("foo") }
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/reference/metaprogramming/macros.md
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ you can expand code at runtime with a method `run`. There is also a problem with
that invokation of `run` in splices. Consider the following expression:

```scala
'{ (x: Int) => ${ ('x).run; 1 } }
'{ (x: Int) => ${ run('x); 1 } }
```
This is again phase correct, but will lead us into trouble. Indeed, evaluating
the splice will reduce the expression `('x).run` to `x`. But then the result
Expand Down
6 changes: 4 additions & 2 deletions docs/docs/reference/metaprogramming/staging.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Run provides a `QuoteContext` that can be used to show the expression in the sco
On the other hand `withQuoteContext` provides a `QuoteContext` without evauating the expression.

```scala
package scala.quoted
package scala.quoted.staging

def run[T](expr: given QuoteContext => Expr[T]) given (toolbox: Toolbox): T = ...

Expand All @@ -81,8 +81,10 @@ expression at runtime. Within the scope of `run` we can also invoke `show` on an
to get a source-like representation of the expression.

```scala
import scala.quoted.staging._

// make available the necessary toolbox for runtime code generation
implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make(getClass.getClassLoader)
delegate for Toolbox = Toolbox.make(getClass.getClassLoader)

val f: Array[Int] => Int = run {
val stagedSum: Expr[Array[Int] => Int] = '{ (arr: Array[Int]) => ${sum('arr)}}
Expand Down
43 changes: 0 additions & 43 deletions library/src-bootstrapped/scala/quoted/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,6 @@ package scala

package object quoted {

/** Evaluate the contents of this expression and return the result.
* It provides a new QuoteContext that is only valid within the scope the argument.
*
* Usage:
* ```
* val e: T = run { // (given qctx: QuoteContext) =>
* expr
* }
* ```
* where `expr: Expr[T]`
*
* This method should not be called in a context where there is already has a `QuoteContext`
* such as within a `run` or a `withQuoteContext`.
*/
def run[T](expr: given QuoteContext => Expr[T]) given (toolbox: Toolbox): T = toolbox.run(expr given _)

/** Provide a new quote context within the scope of the argument that is only valid within the scope the argument.
* Return the result of the argument.
*
* Usage:
* ```
* val e: T = withQuoteContext { // (given qctx: QuoteContext) =>
* thunk
* }
* ```
* where `thunk: T`
*
* This method should not be called in a context where there is already has a `QuoteContext`
* such as within a `run` or a `withQuoteContext`.
*/
def withQuoteContext[T](thunk: given QuoteContext => T) given (toolbox: Toolbox): T = {
var result: T = NoResult.asInstanceOf[T]
def dummyRun given QuoteContext: Expr[Unit] = {
result = thunk
Expr.unitExpr
}
toolbox.run(dummyRun given _)
assert(result != NoResult) // toolbox.run should have thrown an exception
result
}

private object NoResult

object autolift {
given autoToExpr[T] as Conversion[T, Expr[T]] given Liftable[T], QuoteContext = _.toExpr
}
Expand Down
48 changes: 48 additions & 0 deletions library/src-bootstrapped/scala/quoted/staging/package.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package scala.quoted

package object staging {

/** Evaluate the contents of this expression and return the result.
* It provides a new QuoteContext that is only valid within the scope the argument.
*
* Usage:
* ```
* val e: T = run { // (given qctx: QuoteContext) =>
* expr
* }
* ```
* where `expr: Expr[T]`
*
* This method should not be called in a context where there is already has a `QuoteContext`
* such as within a `run` or a `withQuoteContext`.
*/
def run[T](expr: given QuoteContext => Expr[T]) given (toolbox: Toolbox): T = toolbox.run(expr given _)

/** Provide a new quote context within the scope of the argument that is only valid within the scope the argument.
* Return the result of the argument.
*
* Usage:
* ```
* val e: T = withQuoteContext { // (given qctx: QuoteContext) =>
* thunk
* }
* ```
* where `thunk: T`
*
* This method should not be called in a context where there is already has a `QuoteContext`
* such as within a `run` or a `withQuoteContext`.
*/
def withQuoteContext[T](thunk: given QuoteContext => T) given (toolbox: Toolbox): T = {
var result: T = NoResult.asInstanceOf[T]
def dummyRun given QuoteContext: Expr[Unit] = {
result = thunk
Expr.unitExpr
}
toolbox.run(dummyRun given _)
assert(result != NoResult) // toolbox.run should have thrown an exception
result
}

private object NoResult

}
43 changes: 0 additions & 43 deletions library/src-non-bootstrapped/scala/quoted/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,6 @@ package scala

package object quoted {

/** Evaluate the contents of this expression and return the result.
* It provides a new QuoteContext that is only valid within the scope the argument.
*
* Usage:
* ```
* val e: T = run { // (given qctx: QuoteContext) =>
* expr
* }
* ```
* where `expr: Expr[T]`
*
* This method should not be called in a context where there is already has a `QuoteContext`
* such as within a `run` or a `withQuoteContext`.
*/
def run[T](expr: given QuoteContext => Expr[T]) given (toolbox: Toolbox): T = toolbox.run(expr given _)

/** Provide a new quote context within the scope of the argument that is only valid within the scope the argument.
* Return the result of the argument.
*
* Usage:
* ```
* val e: T = withQuoteContext { // (given qctx: QuoteContext) =>
* thunk
* }
* ```
* where `thunk: T`
*
* This method should not be called in a context where there is already has a `QuoteContext`
* such as within a `run` or a `withQuoteContext`.
*/
def withQuoteContext[T](thunk: given QuoteContext => T) given (toolbox: Toolbox): T = {
var result: T = NoResult.asInstanceOf[T]
def dummyRun given QuoteContext: Expr[Unit] = {
result = thunk
Expr.unitExpr
}
toolbox.run(dummyRun given _)
assert(result != NoResult) // toolbox.run should have thrown an exception
result
}

private object NoResult

object autolift {
given autoToExpr[T] as Conversion[T, Expr[T]] given Liftable[T], QuoteContext = _.toExpr
}
Expand Down
1 change: 1 addition & 0 deletions library/src/scala/quoted/Expr.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package scala
package quoted {

import scala.quoted.show.SyntaxHighlight
import scala.quoted.staging.Toolbox

sealed trait Expr[+T] {

Expand Down
3 changes: 3 additions & 0 deletions library/src/scala/quoted/staging/RunScopeException.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package scala.quoted.staging

class RunScopeException extends Exception("Cannot call `scala.quoted.staging.run(...)` within a macro or another `run(...)`")
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package scala.quoted
package staging

import scala.annotation.implicitNotFound

@implicitNotFound("Could not find implicit quoted.Toolbox.\n\nDefault toolbox can be instantiated with:\n `implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make(getClass.getClassLoader)`\n\n")
@implicitNotFound("Could not find implicit scala.quoted.staging.Toolbox.\n\nDefault toolbox can be instantiated with:\n `delegate for scala.quoted.staging.Toolbox = scala.quoted.staging.Toolbox.make(getClass.getClassLoader)`\n\n")
trait Toolbox {
def run[T](expr: QuoteContext => Expr[T]): T
}
Expand All @@ -13,7 +14,8 @@ object Toolbox {
*
* Usuage:
* ```
* implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make(getClass.getClassLoader)
* import scala.quoted.staging._
* delegate for Toolbox = Toolbox.make(getClass.getClassLoader)
* ```
*
* @param appClassloader classloader of the application that generated the quotes
Expand Down Expand Up @@ -55,8 +57,4 @@ object Toolbox {
new Settings(outDir, showRawTree, compilerArgs)
}

class ToolboxNotFoundException(msg: String, cause: ClassNotFoundException) extends Exception(msg, cause)

class RunScopeException extends Exception("Cannot call `scala.quoted.run(...)` within a macro or another `run(...)`")

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package scala.quoted.staging

class ToolboxNotFoundException(msg: String, cause: ClassNotFoundException) extends Exception(msg, cause)
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import scala.quoted._

object Main {

implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make(getClass.getClassLoader)
implicit val toolbox: scala.quoted.staging.Toolbox = scala.quoted.staging.Toolbox.make(getClass.getClassLoader)

def main(args: Array[String]): Unit = {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import scala.quoted._

class Tests {

implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make(getClass.getClassLoader)
implicit val toolbox: scala.quoted.staging.Toolbox = scala.quoted.staging.Toolbox.make(getClass.getClassLoader)

@Test def test(): Unit = {
import hello.Main._
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ object Macros {

inline def foo(i: => Int): Int = ${ fooImpl('i) }
def fooImpl(i: Expr[Int]) given QuoteContext: Expr[Int] = {
implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make(getClass.getClassLoader)
delegate for Toolbox = Toolbox.make(getClass.getClassLoader)
val y: Int = run(i)
y
}
Expand Down
2 changes: 1 addition & 1 deletion tests/neg-with-compiler/i5941/macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ object Lens {
}

def impl[S: Type, T: Type](getter: Expr[S => T]) given (qctx: QuoteContext): Expr[Lens[S, T]] = {
implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make(this.getClass.getClassLoader)
implicit val toolbox: scala.quoted.staging.Toolbox = scala.quoted.staging.Toolbox.make(this.getClass.getClassLoader)
import qctx.tasty._
import util._
// obj.copy(field = value)
Expand Down
3 changes: 2 additions & 1 deletion tests/neg-with-compiler/quote-run-in-macro-1/quoted_1.scala
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import scala.quoted._
import scala.quoted.staging._
import given scala.quoted.autolift._

object Macros {

implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make(getClass.getClassLoader)
delegate for Toolbox = Toolbox.make(getClass.getClassLoader)
inline def foo(i: => Int): Int = ${ fooImpl('i) }
def fooImpl(i: Expr[Int]) given QuoteContext: Expr[Int] = {
val y: Int = run(i)
Expand Down
3 changes: 2 additions & 1 deletion tests/pos-with-compiler/quote-0.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import scala.quoted._
import scala.quoted.staging._
import given scala.quoted.autolift._

object Macros {
Expand All @@ -24,7 +25,7 @@ object Macros {

class Test {

implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make(getClass.getClassLoader)
delegate for Toolbox = Toolbox.make(getClass.getClassLoader)

run {
val program = '{
Expand Down
4 changes: 3 additions & 1 deletion tests/pos-with-compiler/quote-assert/quoted_2.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@

import scala.quoted._
import scala.quoted.staging._

import Macros._

object Test {
Expand All @@ -15,6 +17,6 @@ object Test {
${ assertImpl('{x != 0}) }
}

implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make(getClass.getClassLoader)
delegate for Toolbox = Toolbox.make(getClass.getClassLoader)
run(program)
}
1 change: 1 addition & 0 deletions tests/run-macros/i6765/Macro_1.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import scala.quoted._
import scala.quoted.staging._
import given scala.quoted._

given as Toolbox = Toolbox.make(getClass.getClassLoader)
Expand Down
3 changes: 2 additions & 1 deletion tests/run-macros/i6992/Macro_1.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

import scala.quoted._, scala.quoted.matching._
import scala.quoted.staging._
import delegate scala.quoted._

delegate for Toolbox = Toolbox.make(getClass.getClassLoader)
Expand All @@ -16,7 +17,7 @@ object macros {
case '{$x: Foo} => run(x).x.toExpr
}
} catch {
case _: scala.quoted.Toolbox.RunScopeException =>
case _: scala.quoted.staging.RunScopeException =>
'{"OK"}
}
}
Expand Down
3 changes: 2 additions & 1 deletion tests/run-with-compiler/i3823-b.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import scala.quoted._
import scala.quoted.staging._
object Test {
implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make(getClass.getClassLoader)
delegate for Toolbox = Toolbox.make(getClass.getClassLoader)
def main(args: Array[String]): Unit = withQuoteContext {
def f[T](x: Expr[T])(implicit t: Type[T]) = '{
val z: $t = $x
Expand Down
Loading