Skip to content

Move internal Expr and Type implementations into the compiler #10249

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
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
8 changes: 4 additions & 4 deletions compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,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]]
val expr1 = expr.asInstanceOf[scala.quoted.internal.Expr]
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]]
val tpe1 = tpe.asInstanceOf[scala.quoted.internal.Type]
tpe1.checkScopeId(QuoteContextImpl.scopeId)
changeOwnerOfTree(tpe1.typeTree, ctx.owner)
}
Expand Down Expand Up @@ -75,8 +75,8 @@ object PickledQuotes {
override def transform(tree: tpd.Tree)(using Context): tpd.Tree = tree match {
case Hole(isTerm, idx, args) =>
val reifiedArgs = args.map { arg =>
if (arg.isTerm) (using qctx: QuoteContext) => new scala.internal.quoted.Expr(arg, QuoteContextImpl.scopeId)
else new scala.internal.quoted.Type(arg, QuoteContextImpl.scopeId)
if (arg.isTerm) (using qctx: QuoteContext) => new scala.quoted.internal.Expr(arg, QuoteContextImpl.scopeId)
else new scala.quoted.internal.Type(arg, QuoteContextImpl.scopeId)
}
if isTerm then
val quotedExpr = pickledQuote.exprSplice(idx)(reifiedArgs)(dotty.tools.dotc.quoted.QuoteContextImpl())
Expand Down
16 changes: 8 additions & 8 deletions compiler/src/dotty/tools/dotc/quoted/QuoteContextImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext, scala.intern
case _ => false
def asExpr: scala.quoted.Expr[Any] =
if self.isExpr then
new scala.internal.quoted.Expr(self, QuoteContextImpl.this.hashCode)
new scala.quoted.internal.Expr(self, QuoteContextImpl.this.hashCode)
else self match
case TermTypeTest(self) => throw new Exception("Expected an expression. This is a partially applied Term. Try eta-expanding the term first.")
case _ => throw new Exception("Expected a Term but was: " + self)
Expand Down Expand Up @@ -316,11 +316,11 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext, scala.intern
object TermMethodsImpl extends TermMethods:
extension (self: Term):
def seal: scala.quoted.Expr[Any] =
if self.isExpr then new scala.internal.quoted.Expr(self, QuoteContextImpl.this.hashCode)
if self.isExpr then new scala.quoted.internal.Expr(self, QuoteContextImpl.this.hashCode)
else throw new Exception("Cannot seal a partially applied Term. Try eta-expanding the term first.")

def sealOpt: Option[scala.quoted.Expr[Any]] =
if self.isExpr then Some(new scala.internal.quoted.Expr(self, QuoteContextImpl.this.hashCode))
if self.isExpr then Some(new scala.quoted.internal.Expr(self, QuoteContextImpl.this.hashCode))
else None

def tpe: TypeRepr = self.tpe
Expand Down Expand Up @@ -1003,7 +1003,7 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext, scala.intern

object TypeTree extends TypeTreeModule:
def of[T <: AnyKind](using tp: scala.quoted.Type[T]): TypeTree =
tp.asInstanceOf[scala.internal.quoted.Type[TypeTree]].typeTree
tp.asInstanceOf[scala.quoted.internal.Type].typeTree
end TypeTree

object TypeTreeMethodsImpl extends TypeTreeMethods:
Expand Down Expand Up @@ -1572,7 +1572,7 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext, scala.intern

object TypeRepr extends TypeReprModule:
def of[T <: AnyKind](using tp: scala.quoted.Type[T]): TypeRepr =
tp.asInstanceOf[scala.internal.quoted.Type[TypeTree]].typeTree.tpe
tp.asInstanceOf[scala.quoted.internal.Type].typeTree.tpe
def typeConstructorOf(clazz: Class[?]): TypeRepr =
if (clazz.isPrimitive)
if (clazz == classOf[Boolean]) dotc.core.Symbols.defn.BooleanType
Expand Down Expand Up @@ -1609,7 +1609,7 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext, scala.intern
def seal: scala.quoted.Type[_] = self.asType

def asType: scala.quoted.Type[?] =
new scala.internal.quoted.Type(Inferred(self), QuoteContextImpl.this.hashCode)
new scala.quoted.internal.Type(Inferred(self), QuoteContextImpl.this.hashCode)

def =:=(that: TypeRepr): Boolean = self =:= that
def <:<(that: TypeRepr): Boolean = self <:< that
Expand Down Expand Up @@ -2633,11 +2633,11 @@ class QuoteContextImpl private (ctx: Context) extends QuoteContext, scala.intern

def unpickleExpr[T](pickledQuote: PickledQuote): scala.quoted.Expr[T] =
val tree = PickledQuotes.unpickleTerm(pickledQuote)(using reflect.rootContext)
new scala.internal.quoted.Expr(tree, hash).asInstanceOf[scala.quoted.Expr[T]]
new scala.quoted.internal.Expr(tree, hash).asInstanceOf[scala.quoted.Expr[T]]

def unpickleType[T <: AnyKind](pickledQuote: PickledQuote): scala.quoted.Type[T] =
val tree = PickledQuotes.unpickleTypeTree(pickledQuote)(using reflect.rootContext)
new scala.internal.quoted.Type(tree, hash).asInstanceOf[scala.quoted.Type[T]]
new scala.quoted.internal.Type(tree, hash).asInstanceOf[scala.quoted.Type[T]]

object ExprMatch extends ExprMatchModule:
def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutinee: scala.quoted.Expr[Any])(using pattern: scala.quoted.Expr[Any]): Option[Tup] =
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/transform/Splicer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -323,10 +323,10 @@ object Splicer {
}

private def interpretQuote(tree: Tree)(implicit env: Env): Object =
new scala.internal.quoted.Expr(Inlined(EmptyTree, Nil, QuoteUtils.changeOwnerOfTree(tree, ctx.owner)).withSpan(tree.span), QuoteContextImpl.scopeId)
new scala.quoted.internal.Expr(Inlined(EmptyTree, Nil, QuoteUtils.changeOwnerOfTree(tree, ctx.owner)).withSpan(tree.span), QuoteContextImpl.scopeId)

private def interpretTypeQuote(tree: Tree)(implicit env: Env): Object =
new scala.internal.quoted.Type(QuoteUtils.changeOwnerOfTree(tree, ctx.owner), QuoteContextImpl.scopeId)
new scala.quoted.internal.Type(QuoteUtils.changeOwnerOfTree(tree, ctx.owner), QuoteContextImpl.scopeId)

private def interpretLiteral(value: Any)(implicit env: Env): Object =
value.asInstanceOf[Object]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package scala.internal.quoted
package scala.quoted.internal
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we put the implementation in a package e.g. dotty.tools.dotc.quotes or dotty.tools.dotc.meta?

I think it's better to not have the compiler contain a subpackage of a stdlib package.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They need to be inside of the scala package to be able to extend the Expr and Type. Those have private[scala] constructors.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was the solution agreed in the meeting to avoid the need to move the compiler into the scala package.


import scala.quoted._

import dotty.tools.dotc.ast.tpd

/** An Expr backed by a tree. Only the current compiler trees are allowed.
*
* These expressions are used for arguments of macros. They contain and actual tree
* from the program that is being expanded by the macro.
*
* 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(val tree: tpd.Tree, val scopeId: Int) extends scala.quoted.Expr[Any] {
override def equals(that: Any): Boolean = that match {
case that: Expr[_] =>
case that: Expr =>
// 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
Expand All @@ -24,7 +26,7 @@ final class Expr[Tree](val tree: Tree, val scopeId: Int) extends scala.quoted.Ex

def checkScopeId(expectedScopeId: Int): Unit =
if expectedScopeId != scopeId then
throw new Exception("Cannot call `scala.quoted.staging.run(...)` within a macro or another `run(...)`")
throw new ScopeException("Cannot call `scala.quoted.staging.run(...)` within a macro or another `run(...)`")

override def hashCode: Int = tree.hashCode
override def toString: String = "'{ ... }"
Expand Down
3 changes: 3 additions & 0 deletions compiler/src/scala/quoted/internal/ScopeException.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package scala.quoted.internal

class ScopeException(msg: String) extends Exception(msg)
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package scala.internal.quoted
package scala.quoted.internal

import scala.quoted._

import dotty.tools.dotc.ast.tpd

/** Quoted type (or kind) `T` backed by a tree */
final class Type[Tree](val typeTree: Tree, val scopeId: Int) extends scala.quoted.Type[Any] {
final class Type(val typeTree: tpd.Tree, val scopeId: Int) extends scala.quoted.Type[?] {
override def equals(that: Any): Boolean = that match {
case that: Type[_] => typeTree ==
case that: Type => typeTree ==
// TastyTreeExpr are wrappers around trees, therfore they are equals if their trees are equal.
// All scopeId should be equal unless two different runs of the compiler created the trees.
that.typeTree && scopeId == that.scopeId
Expand All @@ -19,7 +21,7 @@ final class Type[Tree](val typeTree: Tree, val scopeId: Int) extends scala.quote

def checkScopeId(expectedScopeId: Int): Unit =
if expectedScopeId != scopeId then
throw new Exception("Cannot call `scala.quoted.staging.run(...)` within a macro or another `run(...)`")
throw new ScopeException("Cannot call `scala.quoted.staging.run(...)` within a macro or another `run(...)`")

override def hashCode: Int = typeTree.hashCode
override def toString: String = "'[ ... ]"
Expand Down
4 changes: 3 additions & 1 deletion staging/src/scala/quoted/staging/Toolbox.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package staging

import scala.annotation.implicitNotFound

import scala.quoted.internal.ScopeException

@implicitNotFound("Could not find implicit scala.quoted.staging.Toolbox.\n\nDefault toolbox can be instantiated with:\n `given scala.quoted.staging.Toolbox = scala.quoted.staging.Toolbox.make(getClass.getClassLoader)`\n\n")
trait Toolbox:
def run[T](expr: QuoteContext => Expr[T]): T
Expand Down Expand Up @@ -31,7 +33,7 @@ object Toolbox:
def run[T](exprBuilder: QuoteContext => Expr[T]): T = synchronized {
try
if (running) // detected nested run
throw new Exception("Cannot call `scala.quoted.staging.run(...)` within a another `run(...)`")
throw new ScopeException("Cannot call `scala.quoted.staging.run(...)` within a another `run(...)`")
running = true
driver.run(exprBuilder, settings)
finally
Expand Down
4 changes: 2 additions & 2 deletions tests/run-staging/i4730.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ object Test {
given Toolbox = Toolbox.make(getClass.getClassLoader)
def ret(using QuoteContext): Expr[Int => Int] = '{ (x: Int) =>
${
val z = run('{x + 1}) // throws Exception("Cannot call `scala.quoted.staging.run(...)` within a another `run(...)`")
val z = run('{x + 1}) // throws scala.quoted.internal.ScopeException =>
Expr(z)
}
}
Expand All @@ -21,7 +21,7 @@ package scala {
run(Test.ret).apply(10)
throw new Exception
} catch {
case ex: Exception if ex.getMessage == "Cannot call `scala.quoted.staging.run(...)` within a another `run(...)`" =>
case ex: Exception if ex.getClass.getName == "scala.quoted.internal.ScopeException" =>
// ok
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/run-staging/i6754.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ package scala {
throw new Exception
} catch {
case ex: java.lang.reflect.InvocationTargetException =>
assert(ex.getTargetException.getMessage == "Cannot call `scala.quoted.staging.run(...)` within a another `run(...)`")
assert(ex.getTargetException.getClass.getName == "scala.quoted.internal.ScopeException")
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/run-staging/i6992/Macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ package scala {
case '{$x: Foo} => Expr(run(x).x)
}
} catch {
case ex: Exception if ex.getMessage == "Cannot call `scala.quoted.staging.run(...)` within a macro or another `run(...)`" =>
case ex: Exception if ex.getClass.getName == "scala.quoted.internal.ScopeException" =>
'{"OK"}
}
}
Expand Down