Skip to content

Commit 5c84e42

Browse files
Merge pull request #10202 from dotty-staging/hide-quote-exceptions
Hide quote related exceptions from users
2 parents 312a420 + bc7d9f7 commit 5c84e42

File tree

15 files changed

+85
-55
lines changed

15 files changed

+85
-55
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,14 @@ object PickledQuotes {
4040
/** Transform the expression into its fully spliced Tree */
4141
def quotedExprToTree[T](expr: quoted.Expr[T])(using Context): Tree = {
4242
val expr1 = expr.asInstanceOf[scala.internal.quoted.Expr[Tree]]
43-
QuoteContextImpl.checkScopeId(expr1.scopeId)
43+
expr1.checkScopeId(QuoteContextImpl.scopeId)
4444
changeOwnerOfTree(expr1.tree, ctx.owner)
4545
}
4646

4747
/** Transform the expression into its fully spliced TypeTree */
4848
def quotedTypeToTree(tpe: quoted.Type[?])(using Context): Tree = {
4949
val tpe1 = tpe.asInstanceOf[scala.internal.quoted.Type[Tree]]
50-
QuoteContextImpl.checkScopeId(tpe1.scopeId)
50+
tpe1.checkScopeId(QuoteContextImpl.scopeId)
5151
changeOwnerOfTree(tpe1.typeTree, ctx.owner)
5252
}
5353

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,6 @@ object QuoteContextImpl {
3434
qctx.reflect.TreeMethodsImpl.extension_show(tree)
3535
}
3636

37-
private[dotty] def checkScopeId(id: ScopeId)(using Context): Unit =
38-
if (id != scopeId)
39-
throw new scala.quoted.ScopeException("Cannot call `scala.quoted.staging.run(...)` within a macro or another `run(...)`")
40-
4137
// TODO Explore more fine grained scope ids.
4238
// This id can only differentiate scope extrusion from one compiler instance to another.
4339
private[dotty] def scopeId(using Context): ScopeId =

library/src-bootstrapped/scala/internal/quoted/Expr.scala

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,23 @@ import scala.internal.quoted.CompilerInterface.quoteContextWithCompilerInterface
1010
*
1111
* May contain references to code defined outside this Expr instance.
1212
*/
13-
final class Expr[Tree](val tree: Tree, val scopeId: Int) extends scala.quoted.Expr[Any] {
13+
final class Expr[Tree](val tree: Tree, val scopeId: Int) extends scala.quoted.Expr[Any] {
1414
override def equals(that: Any): Boolean = that match {
1515
case that: Expr[_] =>
16-
// Expr are wrappers around trees, therfore they are equals if their trees are equal.
16+
// Expr are wrappers around trees, therefore they are equals if their trees are equal.
1717
// All scopeId should be equal unless two different runs of the compiler created the trees.
1818
tree == that.tree && scopeId == that.scopeId
1919
case _ => false
2020
}
2121

2222
def unseal(using qctx: QuoteContext): qctx.reflect.Term =
23-
if (qctx.hashCode != scopeId)
24-
throw new scala.quoted.ScopeException("Cannot call `scala.quoted.staging.run(...)` within a macro or another `run(...)`")
23+
checkScopeId(qctx.hashCode)
2524
tree.asInstanceOf[qctx.reflect.Term]
2625

26+
def checkScopeId(expectedScopeId: Int): Unit =
27+
if expectedScopeId != scopeId then
28+
throw new scala.internal.quoted.ScopeException("Cannot call `scala.quoted.staging.run(...)` within a macro or another `run(...)`")
29+
2730
override def hashCode: Int = tree.hashCode
2831
override def toString: String = "'{ ... }"
2932
}

library/src-bootstrapped/scala/internal/quoted/Type.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,13 @@ final class Type[Tree](val typeTree: Tree, val scopeId: Int) extends scala.quote
1515

1616
/** View this expression `quoted.Type[T]` as a `TypeTree` */
1717
def unseal(using qctx: QuoteContext): qctx.reflect.TypeTree =
18-
if (qctx.hashCode != scopeId)
19-
throw new scala.quoted.ScopeException("Cannot call `scala.quoted.staging.run(...)` within a macro or another `run(...)`")
18+
checkScopeId(qctx.hashCode)
2019
typeTree.asInstanceOf[qctx.reflect.TypeTree]
2120

21+
def checkScopeId(expectedScopeId: Int): Unit =
22+
if expectedScopeId != scopeId then
23+
throw new scala.internal.quoted.ScopeException("Cannot call `scala.quoted.staging.run(...)` within a macro or another `run(...)`")
24+
2225
override def hashCode: Int = typeTree.hashCode
2326
override def toString: String = "'[ ... ]"
2427
}

library/src-bootstrapped/scala/quoted/Expr.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ abstract class Expr[+T] private[scala] {
3232
if isExprOf[X] then
3333
this.asInstanceOf[scala.quoted.Expr[X]]
3434
else
35-
throw new tasty.reflect.ExprCastError(
35+
throw new scala.internal.quoted.ExprCastError(
3636
s"""Expr: ${this.show}
3737
|of type: ${this.unseal.tpe.show}
3838
|did not conform to type: ${tp.unseal.tpe.show}

library/src-non-bootstrapped/scala/internal/quoted/Expr.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ import scala.quoted._
1919
}
2020

2121
def unseal(using qctx: QuoteContext): qctx.reflect.Term =
22-
if (qctx.hashCode != scopeId)
23-
throw new scala.quoted.ScopeException("Cannot call `scala.quoted.staging.run(...)` within a macro or another `run(...)`")
24-
tree.asInstanceOf[qctx.reflect.Term]
22+
throw new Exception("Non bootstrapped lib")
23+
24+
def checkScopeId(scopeId: Int): Unit =
25+
throw new Exception("Non bootstrapped lib")
2526

2627
override def hashCode: Int = tree.hashCode
2728
override def toString: String = "'{ ... }"

library/src-non-bootstrapped/scala/internal/quoted/Type.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ final class Type[Tree](val typeTree: Tree, val scopeId: Int) extends scala.quote
1414

1515
/** View this expression `quoted.Type[T]` as a `TypeTree` */
1616
def unseal(using qctx: QuoteContext): qctx.reflect.TypeTree =
17-
if (qctx.hashCode != scopeId)
18-
throw new scala.quoted.ScopeException("Cannot call `scala.quoted.staging.run(...)` within a macro or another `run(...)`")
19-
typeTree.asInstanceOf[qctx.reflect.TypeTree]
17+
throw new Exception("Non bootstrapped lib")
18+
19+
def checkScopeId(scopeId: Int): Unit =
20+
throw new Exception("Non bootstrapped lib")
2021

2122
override def hashCode: Int = typeTree.hashCode
2223
override def toString: String = "'[ ... ]"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package scala.internal.quoted
2+
3+
/** Exception thrown when an `Expr[?]` is casted to a `Expr[U]` and the expression is not of type `U` */
4+
private[scala] class ExprCastError(msg: String) extends Throwable(msg)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package scala.internal.quoted
2+
3+
/** Exception thrown when an Expr or Type is used ouside of the scope where it is valid */
4+
private[scala] class ScopeException(msg: String) extends Exception(msg)

library/src/scala/quoted/ScopeException.scala

Lines changed: 0 additions & 4 deletions
This file was deleted.

library/src/scala/tasty/reflect/ExprCastError.scala

Lines changed: 0 additions & 3 deletions
This file was deleted.

staging/src/scala/quoted/staging/Toolbox.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ object Toolbox:
3131
def run[T](exprBuilder: QuoteContext => Expr[T]): T = synchronized {
3232
try
3333
if (running) // detected nested run
34-
throw new ScopeException("Cannot call `scala.quoted.staging.run(...)` within a another `run(...)`")
34+
throw new scala.internal.quoted.ScopeException("Cannot call `scala.quoted.staging.run(...)` within a another `run(...)`")
3535
running = true
3636
driver.run(exprBuilder, settings)
3737
finally

tests/run-staging/i4730.scala

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,20 @@ object Test {
1010
}
1111
}
1212
def main(args: Array[String]): Unit = {
13-
try {
14-
run(ret).apply(10)
15-
throw new Exception
16-
} catch {
17-
case ex: scala.quoted.ScopeException =>
18-
// ok
13+
scala.mytest.myTest()
14+
}
15+
}
16+
17+
package scala {
18+
package mytest {
19+
def myTest()(using Toolbox) = {
20+
try {
21+
run(Test.ret).apply(10)
22+
throw new Exception
23+
} catch {
24+
case ex: scala.internal.quoted.ScopeException =>
25+
// ok
26+
}
1927
}
2028
}
2129
}

tests/run-staging/i6754.scala

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,27 @@ import scala.quoted._
33
import scala.quoted.staging._
44

55
object Test {
6-
implicit val tbx: scala.quoted.staging.Toolbox = scala.quoted.staging.Toolbox.make(getClass.getClassLoader)
6+
def main(args: Array[String]): Unit =
7+
scala.MyTest.myTest()
8+
}
79

8-
def main(args: Array[String]): Unit = {
9-
def y(using QuoteContext): Expr[Unit] = '{
10-
def x(using QuoteContext): Expr[Unit] = '{println("bar")}
11-
println("foo")
12-
run(x)
13-
}
14-
try {
15-
run(y)
16-
throw new Exception
17-
} catch {
18-
case ex: java.lang.reflect.InvocationTargetException =>
19-
assert(ex.getTargetException.isInstanceOf[scala.quoted.ScopeException])
10+
package scala {
11+
object MyTest {
12+
implicit val tbx: scala.quoted.staging.Toolbox = scala.quoted.staging.Toolbox.make(getClass.getClassLoader)
13+
14+
def myTest() = {
15+
def y(using QuoteContext): Expr[Unit] = '{
16+
def x(using QuoteContext): Expr[Unit] = '{println("bar")}
17+
println("foo")
18+
run(x)
19+
}
20+
try {
21+
run(y)
22+
throw new Exception
23+
} catch {
24+
case ex: java.lang.reflect.InvocationTargetException =>
25+
assert(ex.getTargetException.isInstanceOf[scala.internal.quoted.ScopeException])
26+
}
2027
}
2128
}
2229
}

tests/run-staging/i6992/Macro_1.scala

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,32 @@
22
import scala.quoted._
33
import scala.quoted.staging._
44

5-
given Toolbox = Toolbox.make(getClass.getClassLoader)
65

76
object macros {
87
inline def mcr(x: => Any): Any = ${mcrImpl('x)}
98

109
class Foo { val x = 10 }
1110

12-
def mcrImpl(body: Expr[Any])(using ctx: QuoteContext): Expr[Any] = {
13-
import ctx.reflect._
14-
try {
15-
body match {
16-
case '{$x: Foo} => Expr(run(x).x)
11+
def mcrImpl(body: Expr[Any])(using ctx: QuoteContext): Expr[Any] =
12+
MyTest.mcrImpl(body)
13+
}
14+
15+
package scala {
16+
object MyTest {
17+
import macros._
18+
19+
given Toolbox = Toolbox.make(getClass.getClassLoader)
20+
21+
def mcrImpl(body: Expr[Any])(using ctx: QuoteContext): Expr[Any] = {
22+
import ctx.reflect._
23+
try {
24+
body match {
25+
case '{$x: Foo} => Expr(run(x).x)
26+
}
27+
} catch {
28+
case ex: scala.internal.quoted.ScopeException =>
29+
'{"OK"}
1730
}
18-
} catch {
19-
case ex: scala.quoted.ScopeException =>
20-
'{"OK"}
2131
}
2232
}
2333
}

0 commit comments

Comments
 (0)