diff --git a/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala b/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala index efb3f7e0291e..f40f010391cc 100644 --- a/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala +++ b/compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala @@ -40,14 +40,14 @@ object PickledQuotes { /** Transform the expression into its fully spliced Tree */ def quotedExprToTree[T](expr: quoted.Expr[T])(using Context): Tree = { val expr1 = expr.asInstanceOf[scala.internal.quoted.Expr[Tree]] - QuoteContextImpl.checkScopeId(expr1.scopeId) + expr1.checkScopeId(QuoteContextImpl.scopeId) changeOwnerOfTree(expr1.tree, ctx.owner) } /** Transform the expression into its fully spliced TypeTree */ def quotedTypeToTree(tpe: quoted.Type[?])(using Context): Tree = { val tpe1 = tpe.asInstanceOf[scala.internal.quoted.Type[Tree]] - QuoteContextImpl.checkScopeId(tpe1.scopeId) + tpe1.checkScopeId(QuoteContextImpl.scopeId) changeOwnerOfTree(tpe1.typeTree, ctx.owner) } diff --git a/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala b/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala index 6d820094c216..ddb5a551a118 100644 --- a/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala +++ b/compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala @@ -34,10 +34,6 @@ object QuoteContextImpl { qctx.reflect.TreeMethodsImpl.extension_show(tree) } - private[dotty] def checkScopeId(id: ScopeId)(using Context): Unit = - if (id != scopeId) - throw new scala.quoted.ScopeException("Cannot call `scala.quoted.staging.run(...)` within a macro or another `run(...)`") - // TODO Explore more fine grained scope ids. // This id can only differentiate scope extrusion from one compiler instance to another. private[dotty] def scopeId(using Context): ScopeId = diff --git a/library/src-bootstrapped/scala/internal/quoted/Expr.scala b/library/src-bootstrapped/scala/internal/quoted/Expr.scala index 3bb78a5ae035..724da7e24b74 100644 --- a/library/src-bootstrapped/scala/internal/quoted/Expr.scala +++ b/library/src-bootstrapped/scala/internal/quoted/Expr.scala @@ -10,20 +10,23 @@ import scala.internal.quoted.CompilerInterface.quoteContextWithCompilerInterface * * May contain references to code defined outside this Expr instance. */ - final class Expr[Tree](val tree: Tree, val scopeId: Int) extends scala.quoted.Expr[Any] { +final class Expr[Tree](val tree: Tree, val scopeId: Int) extends scala.quoted.Expr[Any] { override def equals(that: Any): Boolean = that match { case that: Expr[_] => - // Expr are wrappers around trees, therfore they are equals if their trees are equal. + // Expr are wrappers around trees, therefore they are equals if their trees are equal. // All scopeId should be equal unless two different runs of the compiler created the trees. tree == that.tree && scopeId == that.scopeId case _ => false } def unseal(using qctx: QuoteContext): qctx.reflect.Term = - if (qctx.hashCode != scopeId) - throw new scala.quoted.ScopeException("Cannot call `scala.quoted.staging.run(...)` within a macro or another `run(...)`") + checkScopeId(qctx.hashCode) tree.asInstanceOf[qctx.reflect.Term] + def checkScopeId(expectedScopeId: Int): Unit = + if expectedScopeId != scopeId then + throw new scala.internal.quoted.ScopeException("Cannot call `scala.quoted.staging.run(...)` within a macro or another `run(...)`") + override def hashCode: Int = tree.hashCode override def toString: String = "'{ ... }" } diff --git a/library/src-bootstrapped/scala/internal/quoted/Type.scala b/library/src-bootstrapped/scala/internal/quoted/Type.scala index cbe730578d51..a4fc80f0dc8d 100644 --- a/library/src-bootstrapped/scala/internal/quoted/Type.scala +++ b/library/src-bootstrapped/scala/internal/quoted/Type.scala @@ -15,10 +15,13 @@ final class Type[Tree](val typeTree: Tree, val scopeId: Int) extends scala.quote /** View this expression `quoted.Type[T]` as a `TypeTree` */ def unseal(using qctx: QuoteContext): qctx.reflect.TypeTree = - if (qctx.hashCode != scopeId) - throw new scala.quoted.ScopeException("Cannot call `scala.quoted.staging.run(...)` within a macro or another `run(...)`") + checkScopeId(qctx.hashCode) typeTree.asInstanceOf[qctx.reflect.TypeTree] + def checkScopeId(expectedScopeId: Int): Unit = + if expectedScopeId != scopeId then + throw new scala.internal.quoted.ScopeException("Cannot call `scala.quoted.staging.run(...)` within a macro or another `run(...)`") + override def hashCode: Int = typeTree.hashCode override def toString: String = "'[ ... ]" } diff --git a/library/src-bootstrapped/scala/quoted/Expr.scala b/library/src-bootstrapped/scala/quoted/Expr.scala index 39b32d7e590b..1baab90f23d8 100644 --- a/library/src-bootstrapped/scala/quoted/Expr.scala +++ b/library/src-bootstrapped/scala/quoted/Expr.scala @@ -32,7 +32,7 @@ abstract class Expr[+T] private[scala] { if isExprOf[X] then this.asInstanceOf[scala.quoted.Expr[X]] else - throw new tasty.reflect.ExprCastError( + throw new scala.internal.quoted.ExprCastError( s"""Expr: ${this.show} |of type: ${this.unseal.tpe.show} |did not conform to type: ${tp.unseal.tpe.show} diff --git a/library/src-non-bootstrapped/scala/internal/quoted/Expr.scala b/library/src-non-bootstrapped/scala/internal/quoted/Expr.scala index 2682c3d8d99a..dbec80ac3a46 100644 --- a/library/src-non-bootstrapped/scala/internal/quoted/Expr.scala +++ b/library/src-non-bootstrapped/scala/internal/quoted/Expr.scala @@ -19,9 +19,10 @@ import scala.quoted._ } def unseal(using qctx: QuoteContext): qctx.reflect.Term = - if (qctx.hashCode != scopeId) - throw new scala.quoted.ScopeException("Cannot call `scala.quoted.staging.run(...)` within a macro or another `run(...)`") - tree.asInstanceOf[qctx.reflect.Term] + throw new Exception("Non bootstrapped lib") + + def checkScopeId(scopeId: Int): Unit = + throw new Exception("Non bootstrapped lib") override def hashCode: Int = tree.hashCode override def toString: String = "'{ ... }" diff --git a/library/src-non-bootstrapped/scala/internal/quoted/Type.scala b/library/src-non-bootstrapped/scala/internal/quoted/Type.scala index 329158243a35..6a4d17eebe60 100644 --- a/library/src-non-bootstrapped/scala/internal/quoted/Type.scala +++ b/library/src-non-bootstrapped/scala/internal/quoted/Type.scala @@ -14,9 +14,10 @@ final class Type[Tree](val typeTree: Tree, val scopeId: Int) extends scala.quote /** View this expression `quoted.Type[T]` as a `TypeTree` */ def unseal(using qctx: QuoteContext): qctx.reflect.TypeTree = - if (qctx.hashCode != scopeId) - throw new scala.quoted.ScopeException("Cannot call `scala.quoted.staging.run(...)` within a macro or another `run(...)`") - typeTree.asInstanceOf[qctx.reflect.TypeTree] + throw new Exception("Non bootstrapped lib") + + def checkScopeId(scopeId: Int): Unit = + throw new Exception("Non bootstrapped lib") override def hashCode: Int = typeTree.hashCode override def toString: String = "'[ ... ]" diff --git a/library/src/scala/internal/quoted/ExprCastError.scala b/library/src/scala/internal/quoted/ExprCastError.scala new file mode 100644 index 000000000000..75e7f8e6b6b9 --- /dev/null +++ b/library/src/scala/internal/quoted/ExprCastError.scala @@ -0,0 +1,4 @@ +package scala.internal.quoted + +/** Exception thrown when an `Expr[?]` is casted to a `Expr[U]` and the expression is not of type `U` */ +private[scala] class ExprCastError(msg: String) extends Throwable(msg) diff --git a/library/src/scala/internal/quoted/ScopeException.scala b/library/src/scala/internal/quoted/ScopeException.scala new file mode 100644 index 000000000000..30b23905eef3 --- /dev/null +++ b/library/src/scala/internal/quoted/ScopeException.scala @@ -0,0 +1,4 @@ +package scala.internal.quoted + +/** Exception thrown when an Expr or Type is used ouside of the scope where it is valid */ +private[scala] class ScopeException(msg: String) extends Exception(msg) diff --git a/library/src/scala/quoted/ScopeException.scala b/library/src/scala/quoted/ScopeException.scala deleted file mode 100644 index b6ecdc8feca3..000000000000 --- a/library/src/scala/quoted/ScopeException.scala +++ /dev/null @@ -1,4 +0,0 @@ -package scala.quoted - -/** Exception thrown when an Expr or Type is used ouside of the scope where it is valid */ -class ScopeException(msg: String) extends Exception(msg) diff --git a/library/src/scala/tasty/reflect/ExprCastError.scala b/library/src/scala/tasty/reflect/ExprCastError.scala deleted file mode 100644 index 5098f11ec0f1..000000000000 --- a/library/src/scala/tasty/reflect/ExprCastError.scala +++ /dev/null @@ -1,3 +0,0 @@ -package scala.tasty.reflect - -class ExprCastError(msg: String) extends Throwable(msg) diff --git a/staging/src/scala/quoted/staging/Toolbox.scala b/staging/src/scala/quoted/staging/Toolbox.scala index a911c24a58de..765ef0b29b99 100644 --- a/staging/src/scala/quoted/staging/Toolbox.scala +++ b/staging/src/scala/quoted/staging/Toolbox.scala @@ -31,7 +31,7 @@ object Toolbox: def run[T](exprBuilder: QuoteContext => Expr[T]): T = synchronized { try if (running) // detected nested run - throw new ScopeException("Cannot call `scala.quoted.staging.run(...)` within a another `run(...)`") + throw new scala.internal.quoted.ScopeException("Cannot call `scala.quoted.staging.run(...)` within a another `run(...)`") running = true driver.run(exprBuilder, settings) finally diff --git a/tests/run-staging/i4730.scala b/tests/run-staging/i4730.scala index 148544af238a..19168431def1 100644 --- a/tests/run-staging/i4730.scala +++ b/tests/run-staging/i4730.scala @@ -10,12 +10,20 @@ object Test { } } def main(args: Array[String]): Unit = { - try { - run(ret).apply(10) - throw new Exception - } catch { - case ex: scala.quoted.ScopeException => - // ok + scala.mytest.myTest() + } +} + +package scala { + package mytest { + def myTest()(using Toolbox) = { + try { + run(Test.ret).apply(10) + throw new Exception + } catch { + case ex: scala.internal.quoted.ScopeException => + // ok + } } } } diff --git a/tests/run-staging/i6754.scala b/tests/run-staging/i6754.scala index 2fbc6ae7e27e..6530d297f122 100644 --- a/tests/run-staging/i6754.scala +++ b/tests/run-staging/i6754.scala @@ -3,20 +3,27 @@ import scala.quoted._ import scala.quoted.staging._ object Test { - implicit val tbx: scala.quoted.staging.Toolbox = scala.quoted.staging.Toolbox.make(getClass.getClassLoader) + def main(args: Array[String]): Unit = + scala.MyTest.myTest() +} - def main(args: Array[String]): Unit = { - def y(using QuoteContext): Expr[Unit] = '{ - def x(using QuoteContext): Expr[Unit] = '{println("bar")} - println("foo") - run(x) - } - try { - run(y) - throw new Exception - } catch { - case ex: java.lang.reflect.InvocationTargetException => - assert(ex.getTargetException.isInstanceOf[scala.quoted.ScopeException]) +package scala { + object MyTest { + implicit val tbx: scala.quoted.staging.Toolbox = scala.quoted.staging.Toolbox.make(getClass.getClassLoader) + + def myTest() = { + def y(using QuoteContext): Expr[Unit] = '{ + def x(using QuoteContext): Expr[Unit] = '{println("bar")} + println("foo") + run(x) + } + try { + run(y) + throw new Exception + } catch { + case ex: java.lang.reflect.InvocationTargetException => + assert(ex.getTargetException.isInstanceOf[scala.internal.quoted.ScopeException]) + } } } } diff --git a/tests/run-staging/i6992/Macro_1.scala b/tests/run-staging/i6992/Macro_1.scala index 0ec6ef2cb805..950ff8efc87e 100644 --- a/tests/run-staging/i6992/Macro_1.scala +++ b/tests/run-staging/i6992/Macro_1.scala @@ -2,22 +2,32 @@ import scala.quoted._ import scala.quoted.staging._ -given Toolbox = Toolbox.make(getClass.getClassLoader) object macros { inline def mcr(x: => Any): Any = ${mcrImpl('x)} class Foo { val x = 10 } - def mcrImpl(body: Expr[Any])(using ctx: QuoteContext): Expr[Any] = { - import ctx.reflect._ - try { - body match { - case '{$x: Foo} => Expr(run(x).x) + def mcrImpl(body: Expr[Any])(using ctx: QuoteContext): Expr[Any] = + MyTest.mcrImpl(body) +} + +package scala { + object MyTest { + import macros._ + + given Toolbox = Toolbox.make(getClass.getClassLoader) + + def mcrImpl(body: Expr[Any])(using ctx: QuoteContext): Expr[Any] = { + import ctx.reflect._ + try { + body match { + case '{$x: Foo} => Expr(run(x).x) + } + } catch { + case ex: scala.internal.quoted.ScopeException => + '{"OK"} } - } catch { - case ex: scala.quoted.ScopeException => - '{"OK"} } } }