Skip to content

Commit 300c37e

Browse files
committed
Don't require implicits to make type refs persist stages
It turns out that we can always make type references cross-stage persistent because we can create a `quoted.Type[T]` from any type `T`. So implicit search is not needed, after all. This means we don't need anymore the infrastructure of allowing implicit searches in macro transforms. But we don't remove it because it might become useful later.
1 parent dbb7c81 commit 300c37e

File tree

4 files changed

+26
-49
lines changed

4 files changed

+26
-49
lines changed

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

Lines changed: 21 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,13 @@ import util.Positions._
99
import StdNames._
1010
import ast.untpd
1111
import MegaPhase.MiniPhase
12-
import typer.Implicits._
1312
import NameKinds.OuterSelectName
1413
import scala.collection.mutable
1514

1615
/** Translates quoted terms and types to `unpickle` method calls.
1716
* Checks that the phase consistency principle (PCP) holds.
1817
*/
19-
class ReifyQuotes extends MacroTransformWithImplicits {
18+
class ReifyQuotes extends MacroTransform {
2019
import ast.tpd._
2120

2221
override def phaseName: String = "reifyQuotes"
@@ -41,7 +40,7 @@ class ReifyQuotes extends MacroTransformWithImplicits {
4140
def pickleTree(tree: Tree, isType: Boolean)(implicit ctx: Context): String =
4241
tree.show // TODO: replace with TASTY
4342

44-
private class Reifier extends ImplicitsTransformer {
43+
private class Reifier extends Transformer {
4544

4645
/** A class for collecting the splices of some quoted expression */
4746
private class Splices {
@@ -83,7 +82,7 @@ class ReifyQuotes extends MacroTransformWithImplicits {
8382
val (trefs, tags) = assocs.unzip
8483
tags ++=: buf
8584
typeTagOfRef.clear()
86-
Block(typeDefs, expr).subst(trefs.map(_.symbol), typeDefs.map(_.symbol))
85+
Block(typeDefs, expr.subst(trefs.map(_.symbol), typeDefs.map(_.symbol)))
8786
}
8887
}
8988

@@ -113,39 +112,17 @@ class ReifyQuotes extends MacroTransformWithImplicits {
113112
* check that its staging level matches the current level. References to types
114113
* that are phase-incorrect can still be healed as follows.
115114
*
116-
* If `T` is a reference to a type at the wrong level, and there is an implicit value `tag`
117-
* of type `quoted.Type[T]`, transform `tag` yielding `tag1` and add the binding `T -> tag1`
118-
* to the `typeTagOfRef` map of the current `Splices` structure. These entries will be turned
119-
* info additional type definitions in method `addTags`.
115+
* If `T` is a reference to a type at the wrong level, heal it by setting things up
116+
* so that we later add a type definition
117+
*
118+
* type T' = ~quoted.Type[T]
119+
*
120+
* to the quoted text and rename T to T' in it. This is done later in `reify` via
121+
* `Splice#addTags`. checkLevel itself only records what needs to be done in the
122+
* `typeTagOfRef` field of the current `Splice` structure.
120123
*/
121124
private def checkLevel(tree: Tree)(implicit ctx: Context): Tree = {
122125

123-
/** Try to heal phase-inconsistent reference to type `T` using a local type definition.
124-
* @return None if successful
125-
* @return Some(msg) if unsuccessful where `msg` is a potentially empty error message
126-
* to be added to the "inconsistent phase" message.
127-
*/
128-
def heal(tp: Type): Option[String] = tp match {
129-
case tp: TypeRef =>
130-
val reqType = defn.QuotedTypeType.appliedTo(tp)
131-
val tag = ctx.typer.inferImplicitArg(reqType, tree.pos)
132-
tag.tpe match {
133-
case fail: SearchFailureType =>
134-
Some(i"""
135-
|
136-
| The access would be accepted with the right type tag, but
137-
| ${ctx.typer.missingArgMsg(tag, reqType, "")}""")
138-
case _ =>
139-
splicesAtLevel(currentLevel).typeTagOfRef(tp) = {
140-
currentLevel -= 1
141-
try transform(tag) finally currentLevel += 1
142-
}
143-
None
144-
}
145-
case _ =>
146-
Some("")
147-
}
148-
149126
/** Check reference to `sym` for phase consistency, where `tp` is the underlying type
150127
* by which we refer to `sym`.
151128
*/
@@ -160,12 +137,18 @@ class ReifyQuotes extends MacroTransformWithImplicits {
160137
else if (sym.exists && !sym.isStaticOwner &&
161138
!ctx.owner.ownersIterator.exists(_.isInlineMethod) &&
162139
levelOf.getOrElse(sym, currentLevel) != currentLevel)
163-
heal(tp) match {
164-
case Some(errMsg) =>
140+
tp match {
141+
case tp: TypeRef =>
142+
// Legalize reference to phase-inconstent type
143+
splicesAtLevel(currentLevel).typeTagOfRef(tp) = {
144+
currentLevel -= 1
145+
val tag = New(defn.QuotedTypeType.appliedTo(tp), Nil)
146+
try transform(tag) finally currentLevel += 1
147+
}
148+
case _ =>
165149
ctx.error(em"""access to $symStr from wrong staging level:
166150
| - the definition is at level ${levelOf(sym)},
167-
| - but the access is at level $currentLevel.$errMsg""", tree.pos)
168-
case None =>
151+
| - but the access is at level $currentLevel.""", tree.pos)
169152
}
170153
}
171154

tests/neg/quoteTest.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class Test {
1515
'((y: Expr[Int]) => ~y ) // error: wrong staging level
1616

1717
def f[T](t: Type[T], x: Expr[T]) = '{
18-
val z2 = ~x // error: wrong staging level for type T
18+
val z2 = ~x // OK
1919
}
2020

2121
}

tests/pos/quoteTest.scala

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,7 @@ import scala.quoted._
22

33
object Test {
44

5-
def f[T](x: Expr[T])(t0: Type[T]) = {
6-
implicit val t: Type[T] = t0
7-
'{
8-
val y: t.unary_~ = x.unary_~
9-
val z = ~x
10-
}
11-
}
12-
13-
def f2[T](x: Expr[T])(implicit t: Type[T]) = '{
5+
def f[T](x: Expr[T])(t: Type[T]) = '{
146
val y: t.unary_~ = x.unary_~
157
val z = ~x
168
}

tests/pos/stagedInterpreter.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ object Test {
2727
compile(body, env + (x -> compile(e, env)))
2828
}
2929

30-
val res1 = (x: Int) => ~compile(exp, Map("x" -> '(x)))
30+
val res1 = '{ (x: Int) => ~compile(exp, Map("x" -> '(x))) }
3131

3232
val res2 = compile(letExp, Map())
33+
34+
res1.run
3335
}

0 commit comments

Comments
 (0)