Skip to content

Commit bb7c869

Browse files
committed
Fix #4730: Detect nested calls to run on the same toolbox
1 parent 13da159 commit bb7c869

File tree

6 files changed

+40
-5
lines changed

6 files changed

+40
-5
lines changed

compiler/src/dotty/tools/dotc/quoted/ToolboxImpl.scala

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,17 @@ object ToolboxImpl {
1515

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

18+
private[this] var running = false
19+
1820
def run[T](exprBuilder: QuoteContext => Expr[T]): T = synchronized {
19-
driver.run(exprBuilder, settings)
21+
try {
22+
if (running) // detected nested run
23+
throw new scala.quoted.Toolbox.ToolboxAlreadyRunning()
24+
running = true
25+
driver.run(exprBuilder, settings)
26+
} finally {
27+
running = false
28+
}
2029
}
2130

2231
}

library/src/scala/quoted/Toolbox.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,7 @@ object Toolbox {
5656
}
5757

5858
class ToolboxNotFoundException(msg: String, cause: ClassNotFoundException) extends Exception(msg, cause)
59+
60+
class ToolboxAlreadyRunning extends Exception("Cannot call `scala.quoted.run(...)` within another `run(...)`")
61+
5962
}

library/src/scala/quoted/package.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ package object quoted {
1515
*
1616
* This method should not be called in a context where there is already has a `QuoteContext`
1717
* such as within a `run` or a `withQuoteContext`.
18-
*
19-
* May throw a FreeVariableError on expressions that came from a macro.
2018
*/
2119
def run[T](expr: given QuoteContext => Expr[T]) given (toolbox: Toolbox): T = toolbox.run(expr given _)
2220

tests/run-with-compiler/i4730.scala

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import scala.quoted._
2+
3+
object Test {
4+
implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make(getClass.getClassLoader)
5+
def ret given QuoteContext: Expr[Int => Int] = '{ (x: Int) =>
6+
${
7+
val z = run('{x + 1}) // throws a ToolboxAlreadyRunning
8+
z.toExpr
9+
}
10+
}
11+
def main(args: Array[String]): Unit = {
12+
try {
13+
run(ret).apply(10)
14+
throw new Exception
15+
} catch {
16+
case ex: scala.quoted.Toolbox.ToolboxAlreadyRunning =>
17+
// ok
18+
}
19+
}
20+
}

tests/run-with-compiler/i6754.check

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
foo
2-
bar

tests/run-with-compiler/i6754.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ object Test {
1010
println("foo")
1111
run(x)
1212
}
13-
run(y)
13+
try {
14+
run(y)
15+
throw new Exception
16+
} catch {
17+
case ex: java.lang.reflect.InvocationTargetException =>
18+
assert(ex.getTargetException.isInstanceOf[scala.quoted.Toolbox.ToolboxAlreadyRunning])
19+
}
1420
}
1521
}

0 commit comments

Comments
 (0)