Skip to content

Commit 6e18e45

Browse files
committed
Use SpliceScope instead of ScopeId and remove it
1 parent 2a7e910 commit 6e18e45

File tree

7 files changed

+26
-49
lines changed

7 files changed

+26
-49
lines changed

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,13 @@ object PickledQuotes {
4141
/** Transform the expression into its fully spliced Tree */
4242
def quotedExprToTree[T](expr: quoted.Expr[T])(using Context): Tree = {
4343
val expr1 = expr.asInstanceOf[ExprImpl]
44-
expr1.checkScopeId(QuotesImpl.scopeId)
4544
ScopeException.checkInCorrectScope(expr1.scope, SpliceScope.getCurrent, expr1.tree, "Expr")
4645
changeOwnerOfTree(expr1.tree, ctx.owner)
4746
}
4847

4948
/** Transform the expression into its fully spliced TypeTree */
5049
def quotedTypeToTree(tpe: quoted.Type[?])(using Context): Tree = {
5150
val tpe1 = tpe.asInstanceOf[TypeImpl]
52-
tpe1.checkScopeId(QuotesImpl.scopeId)
5351
ScopeException.checkInCorrectScope(tpe1.scope, SpliceScope.getCurrent, tpe1.typeTree, "Type")
5452
changeOwnerOfTree(tpe1.typeTree, ctx.owner)
5553
}
@@ -77,8 +75,8 @@ object PickledQuotes {
7775
case Hole(isTerm, idx, args) =>
7876
inContext(SpliceScope.contextWithNewSpliceScope(tree.sourcePos)) {
7977
val reifiedArgs = args.map { arg =>
80-
if (arg.isTerm) (q: Quotes) ?=> new ExprImpl(arg, QuotesImpl.scopeId, SpliceScope.getCurrent)
81-
else new TypeImpl(arg, QuotesImpl.scopeId, SpliceScope.getCurrent)
78+
if (arg.isTerm) (q: Quotes) ?=> new ExprImpl(arg, SpliceScope.getCurrent)
79+
else new TypeImpl(arg, SpliceScope.getCurrent)
8280
}
8381
if isTerm then
8482
val quotedExpr = termHole(idx, reifiedArgs, QuotesImpl())

compiler/src/dotty/tools/dotc/transform/Splicer.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,10 +326,10 @@ object Splicer {
326326
}
327327

328328
private def interpretQuote(tree: Tree)(implicit env: Env): Object =
329-
new ExprImpl(Inlined(EmptyTree, Nil, QuoteUtils.changeOwnerOfTree(tree, ctx.owner)).withSpan(tree.span), QuotesImpl.scopeId, SpliceScope.getCurrent)
329+
new ExprImpl(Inlined(EmptyTree, Nil, QuoteUtils.changeOwnerOfTree(tree, ctx.owner)).withSpan(tree.span), SpliceScope.getCurrent)
330330

331331
private def interpretTypeQuote(tree: Tree)(implicit env: Env): Object =
332-
new TypeImpl(QuoteUtils.changeOwnerOfTree(tree, ctx.owner), QuotesImpl.scopeId, SpliceScope.getCurrent)
332+
new TypeImpl(QuoteUtils.changeOwnerOfTree(tree, ctx.owner), SpliceScope.getCurrent)
333333

334334
private def interpretLiteral(value: Any)(implicit env: Env): Object =
335335
value.asInstanceOf[Object]

compiler/src/scala/quoted/runtime/impl/ExprImpl.scala

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,14 @@ import dotty.tools.dotc.ast.tpd
1010
*
1111
* May contain references to code defined outside this Expr instance.
1212
*/
13-
final class ExprImpl(val tree: tpd.Tree, val scopeId: Int, val scope: Scope) extends Expr[Any] {
13+
final class ExprImpl(val tree: tpd.Tree, val scope: Scope) extends Expr[Any] {
1414
override def equals(that: Any): Boolean = that match {
1515
case that: ExprImpl =>
1616
// Expr are wrappers around trees, therefore they are equals if their trees are equal.
17-
// All scopeId should be equal unless two different runs of the compiler created the trees.
18-
tree == that.tree && scopeId == that.scopeId
17+
// All scope should be equal unless two different runs of the compiler created the trees.
18+
tree == that.tree && scope == that.scope
1919
case _ => false
2020
}
2121

22-
def checkScopeId(expectedScopeId: Int): Unit =
23-
if expectedScopeId != scopeId then
24-
throw new ScopeException("Cannot call `scala.quoted.staging.run(...)` within a macro or another `run(...)`")
25-
26-
override def hashCode: Int = tree.hashCode
2722
override def toString: String = "'{ ... }"
2823
}

compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ import scala.reflect.TypeTest
2323

2424
object QuotesImpl {
2525

26-
type ScopeId = Int
27-
2826
def apply()(using Context): Quotes =
2927
new QuotesImpl
3028

@@ -34,11 +32,6 @@ object QuotesImpl {
3432
if ctx.settings.color.value == "always" then TreeAnsiCode.show(tree)
3533
else TreeCode.show(tree)
3634

37-
// TODO Explore more fine grained scope ids.
38-
// This id can only differentiate scope extrusion from one compiler instance to another.
39-
def scopeId(using Context): ScopeId =
40-
ctx.outersIterator.toList.last.hashCode()
41-
4235
}
4336

4437
class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler, QuoteMatching:
@@ -81,10 +74,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
8174
end CompilationInfo
8275

8376
extension (expr: Expr[Any])
84-
def asTerm: Term =
85-
val exprImpl = expr.asInstanceOf[ExprImpl]
86-
exprImpl.checkScopeId(QuotesImpl.this.hashCode)
87-
exprImpl.tree
77+
def asTerm: Term = expr.asInstanceOf[ExprImpl].tree
8878
end extension
8979

9080
type Tree = tpd.Tree
@@ -105,7 +95,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
10595
case _ => false
10696
def asExpr: scala.quoted.Expr[Any] =
10797
if self.isExpr then
108-
new ExprImpl(self, QuotesImpl.this.hashCode, SpliceScope.getCurrent)
98+
new ExprImpl(self, SpliceScope.getCurrent)
10999
else self match
110100
case TermTypeTest(self) => throw new Exception("Expected an expression. This is a partially applied Term. Try eta-expanding the term first.")
111101
case _ => throw new Exception("Expected a Term but was: " + self)
@@ -372,11 +362,11 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
372362
given TermMethods: TermMethods with
373363
extension (self: Term)
374364
def seal: scala.quoted.Expr[Any] =
375-
if self.isExpr then new ExprImpl(self, QuotesImpl.this.hashCode, SpliceScope.getCurrent)
365+
if self.isExpr then new ExprImpl(self, SpliceScope.getCurrent)
376366
else throw new Exception("Cannot seal a partially applied Term. Try eta-expanding the term first.")
377367

378368
def sealOpt: Option[scala.quoted.Expr[Any]] =
379-
if self.isExpr then Some(new ExprImpl(self, QuotesImpl.this.hashCode, SpliceScope.getCurrent))
369+
if self.isExpr then Some(new ExprImpl(self, SpliceScope.getCurrent))
380370
else None
381371

382372
def tpe: TypeRepr = self.tpe
@@ -1666,7 +1656,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
16661656
def seal: scala.quoted.Type[_] = self.asType
16671657

16681658
def asType: scala.quoted.Type[?] =
1669-
new TypeImpl(Inferred(self), QuotesImpl.this.hashCode, SpliceScope.getCurrent)
1659+
new TypeImpl(Inferred(self), SpliceScope.getCurrent)
16701660

16711661
def =:=(that: TypeRepr): Boolean = self =:= that
16721662
def <:<(that: TypeRepr): Boolean = self <:< that
@@ -2877,11 +2867,11 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
28772867

28782868
def unpickleExpr[T](pickled: String | List[String], typeHole: (Int, Seq[Any]) => scala.quoted.Type[?], termHole: (Int, Seq[Any], scala.quoted.Quotes) => scala.quoted.Expr[?]): scala.quoted.Expr[T] =
28792869
val tree = PickledQuotes.unpickleTerm(pickled, typeHole, termHole)
2880-
new ExprImpl(tree, hash, SpliceScope.getCurrent).asInstanceOf[scala.quoted.Expr[T]]
2870+
new ExprImpl(tree, SpliceScope.getCurrent).asInstanceOf[scala.quoted.Expr[T]]
28812871

28822872
def unpickleType[T <: AnyKind](pickled: String | List[String], typeHole: (Int, Seq[Any]) => scala.quoted.Type[?], termHole: (Int, Seq[Any], scala.quoted.Quotes) => scala.quoted.Expr[?]): scala.quoted.Type[T] =
28832873
val tree = PickledQuotes.unpickleTypeTree(pickled, typeHole, termHole)
2884-
new TypeImpl(tree, hash, SpliceScope.getCurrent).asInstanceOf[scala.quoted.Type[T]]
2874+
new TypeImpl(tree, SpliceScope.getCurrent).asInstanceOf[scala.quoted.Type[T]]
28852875

28862876
object ExprMatch extends ExprMatchModule:
28872877
def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutinee: scala.quoted.Expr[Any])(using pattern: scala.quoted.Expr[Any]): Option[Tup] =
@@ -2948,7 +2938,4 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
29482938
}
29492939
}
29502940

2951-
private[this] val hash = QuotesImpl.scopeId(using ctx)
2952-
override def hashCode: Int = hash
2953-
29542941
end QuotesImpl

compiler/src/scala/quoted/runtime/impl/ScopeException.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ class ScopeException(msg: String) extends Exception(msg)
77

88
object ScopeException:
99
def checkInCorrectScope(scope: Scope, currentScope: Scope, tree: Tree, kind: String)(using Context): Unit =
10+
if scope.root != currentScope.root then
11+
throw new ScopeException(s"Cannot use $kind oustide of the macro splice `$${...}` or the scala.quoted.staging.run(...)` where it was defined")
12+
1013
val yCheck = ctx.settings.Ycheck.value(using ctx).exists(x => x == "all" || x == "macros")
1114
if yCheck && !scope.isOuterScopeOf(currentScope) then
1215
throw new ScopeException(

compiler/src/scala/quoted/runtime/impl/SpliceScope.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ trait Scope {
1818
/** Is this is a outer scope of the given scope */
1919
def isOuterScopeOf(scope: Scope): Boolean =
2020
this.eq(scope) || (scope.ne(NoScope) && isOuterScopeOf(scope.outer))
21+
/** Scope of he top level splice or staging `run` */
22+
def root: Scope =
23+
if outer.eq(NoScope) then this else outer.root
2124
/** Stack of locations where scopes where evaluated */
2225
def stack: List[String] =
2326
this.toString :: (if outer.eq(NoScope) then Nil else outer.stack)
@@ -27,6 +30,7 @@ trait Scope {
2730

2831
/** Only used for outer scope of top level splice and staging `run` */
2932
object NoScope extends Scope:
33+
override def root: Scope = this
3034
override def outer: Scope = throw UnsupportedOperationException("NoScope.outer")
3135

3236
class SpliceScope(val pos: SourcePosition, override val outer: Scope) extends Scope:
@@ -57,6 +61,6 @@ object SpliceScope:
5761

5862
/** Context with an incremented quotation level. */
5963
def getCurrent(using Context): Scope =
60-
ctx.property(ScopeKey).getOrElse(null)
64+
ctx.property(ScopeKey).getOrElse(NoScope)
6165

6266
end SpliceScope

compiler/src/scala/quoted/runtime/impl/TypeImpl.scala

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,14 @@ package runtime.impl
44
import dotty.tools.dotc.ast.tpd
55

66
/** Quoted type (or kind) `T` backed by a tree */
7-
final class TypeImpl(val typeTree: tpd.Tree, val scopeId: Int, val scope: Scope) extends Type[?] {
7+
final class TypeImpl(val typeTree: tpd.Tree, val scope: Scope) extends Type[?] {
88
override def equals(that: Any): Boolean = that match {
99
case that: TypeImpl => typeTree ==
10-
// TastyTreeExpr are wrappers around trees, therfore they are equals if their trees are equal.
11-
// All scopeId should be equal unless two different runs of the compiler created the trees.
12-
that.typeTree && scopeId == that.scopeId
10+
// TastyTreeExpr are wrappers around trees, therefore they are equals if their trees are equal.
11+
// All scope should be equal unless two different runs of the compiler created the trees.
12+
that.typeTree && scope == that.scope
1313
case _ => false
1414
}
1515

16-
/** View this expression `q.Type[T]` as a `TypeTree` */
17-
def unseal(using q: Quotes): q.reflect.TypeTree =
18-
checkScopeId(q.hashCode)
19-
typeTree.asInstanceOf[q.reflect.TypeTree]
20-
21-
def checkScopeId(expectedScopeId: Int): Unit =
22-
if expectedScopeId != scopeId then
23-
throw new ScopeException("Cannot call `scala.quoted.staging.run(...)` within a macro or another `run(...)`")
24-
25-
override def hashCode: Int = typeTree.hashCode
2616
override def toString: String = "Type.of[...]"
2717
}

0 commit comments

Comments
 (0)