Skip to content

Commit 6c0cce7

Browse files
committed
Move Staging check into typer
1 parent 5ed73e6 commit 6c0cce7

File tree

8 files changed

+87
-62
lines changed

8 files changed

+87
-62
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,11 +1350,6 @@ object desugar {
13501350
val desugared = tree match {
13511351
case SymbolLit(str) =>
13521352
Literal(Constant(scala.Symbol(str)))
1353-
case Quote(expr) =>
1354-
if (expr.isType)
1355-
TypeApply(ref(defn.QuotedType_applyR), List(expr))
1356-
else
1357-
Apply(ref(defn.QuotedExpr_applyR), expr)
13581353
case InterpolatedString(id, segments) =>
13591354
val strs = segments map {
13601355
case ts: Thicket => ts.trees.head

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

Lines changed: 29 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,6 @@ class Staging extends MacroTransform {
3737
import tpd._
3838
import Staging._
3939

40-
/** Classloader used for loading macros */
41-
private[this] var myMacroClassLoader: java.lang.ClassLoader = _
42-
private def macroClassLoader(implicit ctx: Context): ClassLoader = {
43-
if (myMacroClassLoader == null) {
44-
val urls = ctx.settings.classpath.value.split(java.io.File.pathSeparatorChar).map(cp => java.nio.file.Paths.get(cp).toUri.toURL)
45-
myMacroClassLoader = new java.net.URLClassLoader(urls, getClass.getClassLoader)
46-
}
47-
myMacroClassLoader
48-
}
49-
5040
override def phaseName: String = Staging.name
5141

5242
override def allowsImplicitSearch: Boolean = true
@@ -88,39 +78,30 @@ class Staging extends MacroTransform {
8878
new PCPCheckAndHeal(ctx).transform(tree)
8979
}
9080

91-
private class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(ictx) {
9281

93-
override def transform(tree: Tree)(implicit ctx: Context): Tree = {
94-
reporting.trace(i"PCPTransformer.transform $tree at $level", show = true) {
95-
tree match {
96-
case tree: DefDef if tree.symbol.is(Macro) =>
97-
if (level > 0) {
98-
super.transform(tree) // Ignore output, only check PCP
99-
EmptyTree // Already inlined
100-
}
101-
else if (enclosingInlineds.nonEmpty) {
102-
EmptyTree // Already checked at definition site and already inlined
103-
}
104-
else tree.rhs match {
105-
case InlineSplice(_) =>
106-
super.transform(tree) // Ignore output, only check PCP
107-
tree
108-
case _ =>
109-
ctx.error(
110-
"""Malformed macro.
111-
|
112-
|Expected the ~ to be at the top of the RHS:
113-
| inline def foo(inline x: X, ..., y: Y): Int = ~impl(x, ... '(y))
114-
|
115-
| * The contents of the splice must call a static method
116-
| * All arguments must be quoted or inline
117-
""".stripMargin, tree.rhs.sourcePos)
118-
tree
119-
}
120-
case _ =>
121-
checkLevel(super.transform(tree))
122-
}
82+
}
83+
84+
object Staging {
85+
val name: String = "staging"
86+
}
87+
88+
class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(ictx) {
89+
import tpd._
90+
import PCPCheckAndHeal._
91+
92+
/** Classloader used for loading macros */
93+
private[this] var myMacroClassLoader: java.lang.ClassLoader = _
94+
private def macroClassLoader(implicit ctx: Context): ClassLoader = {
95+
if (myMacroClassLoader == null) {
96+
val urls = ctx.settings.classpath.value.split(java.io.File.pathSeparatorChar).map(cp => java.nio.file.Paths.get(cp).toUri.toURL)
97+
myMacroClassLoader = new java.net.URLClassLoader(urls, getClass.getClassLoader)
12398
}
99+
myMacroClassLoader
100+
}
101+
102+
override def transform(tree: Tree)(implicit ctx: Context): Tree = tree match {
103+
case tree: DefDef if tree.symbol.is(Inline) && level > 0 => EmptyTree
104+
case _ => checkLevel(super.transform(tree))
124105
}
125106

126107
/** Transform quoted trees while maintaining phase correctness */
@@ -307,10 +288,16 @@ class Staging extends MacroTransform {
307288
}
308289
}
309290

291+
292+
}
293+
294+
object PCPCheckAndHeal {
295+
import tpd._
296+
310297
/** InlineSplice is used to detect cases where the expansion
311298
* consists of a (possibly multiple & nested) block or a sole expression.
312299
*/
313-
private object InlineSplice {
300+
object InlineSplice {
314301
def unapply(tree: Tree)(implicit ctx: Context): Option[Tree] = tree match {
315302
case Spliced(code) if Splicer.canBeSpliced(code) => Some(code)
316303
case Block(List(stat), Literal(Constant(()))) => unapply(stat)
@@ -319,11 +306,4 @@ class Staging extends MacroTransform {
319306
case _ => None
320307
}
321308
}
322-
323309
}
324-
325-
}
326-
327-
object Staging {
328-
val name: String = "staging"
329-
}

compiler/src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -815,7 +815,6 @@ class Namer { typer: Typer =>
815815
case original: untpd.DefDef if sym.isInlineMethod =>
816816
PrepareInlineable.registerInlineInfo(
817817
sym,
818-
original.rhs,
819818
implicit ctx => typedAheadExpr(original).asInstanceOf[tpd.DefDef].rhs
820819
)(localContext(sym))
821820
case _ =>

compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ object PrepareInlineable {
219219
* to have the inline method as owner.
220220
*/
221221
def registerInlineInfo(
222-
inlined: Symbol, originalBody: untpd.Tree, treeExpr: Context => Tree)(implicit ctx: Context): Unit = {
222+
inlined: Symbol, treeExpr: Context => Tree)(implicit ctx: Context): Unit = {
223223
inlined.unforcedAnnotation(defn.BodyAnnot) match {
224224
case Some(ann: ConcreteBodyAnnotation) =>
225225
case Some(ann: LazyBodyAnnotation) if ann.isEvaluated =>

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import EtaExpansion.etaExpand
2727
import util.Spans._
2828
import util.common._
2929
import util.Property
30-
import Applications.{ExtMethodApply, wrapDefs, productSelectorTypes}
30+
import Applications.{ExtMethodApply, productSelectorTypes, wrapDefs}
3131

3232
import collection.mutable
3333
import annotation.tailrec
@@ -36,6 +36,7 @@ import util.Stats.{record, track}
3636
import config.Printers.{gadts, typr}
3737
import rewrites.Rewrites.patch
3838
import NavigateAST._
39+
import dotty.tools.dotc.transform.{PCPCheckAndHeal, Staging, TreeMapWithStages}
3940
import transform.SymUtils._
4041
import transform.TypeUtils._
4142
import reporting.trace
@@ -1548,7 +1549,39 @@ class Typer extends Namer
15481549
if (sym.isInlineMethod) rhsCtx = rhsCtx.addMode(Mode.InlineableBody)
15491550
val rhs1 = typedExpr(ddef.rhs, tpt1.tpe)(rhsCtx)
15501551

1551-
if (sym.isInlineMethod) PrepareInlineable.registerInlineInfo(sym, ddef.rhs, _ => rhs1)
1552+
if (sym.isInlineMethod) {
1553+
if (ctx.phase.isTyper) {
1554+
import PCPCheckAndHeal.InlineSplice
1555+
import TreeMapWithStages._
1556+
var isMacro = false
1557+
new TreeMapWithStages(freshStagingContext){
1558+
override protected def splice(splice: tpd.Select)(implicit ctx: Context): tpd.Tree = {
1559+
isMacro = true
1560+
splice
1561+
}
1562+
}.transform(rhs1)
1563+
1564+
if (isMacro) {
1565+
sym.setFlag(Macro)
1566+
if (TreeMapWithStages.level == 0)
1567+
rhs1 match {
1568+
case InlineSplice(_) =>
1569+
new PCPCheckAndHeal(freshStagingContext).transform(rhs1) // Ignore output, only check PCP
1570+
case _ =>
1571+
ctx.error(
1572+
"""Malformed macro.
1573+
|
1574+
|Expected the ~ to be at the top of the RHS:
1575+
| inline def foo(inline x: X, ..., y: Y): Int = ~impl(x, ... '(y))
1576+
|
1577+
| * The contents of the splice must call a static method
1578+
| * All arguments must be quoted or inline
1579+
""".stripMargin, ddef.sourcePos)
1580+
}
1581+
}
1582+
}
1583+
PrepareInlineable.registerInlineInfo(sym, _ => rhs1)
1584+
}
15521585

15531586
if (sym.isConstructor && !sym.isPrimaryConstructor)
15541587
for (param <- tparams1 ::: vparamss1.flatten)
@@ -1923,6 +1956,16 @@ class Typer extends Namer
19231956
}
19241957
}
19251958

1959+
/** Translate `'(expr)`/`'{ expr* }` into `scala.quoted.Expr.apply(expr)` and `'[T]` into `scala.quoted.Type.apply[T]`
1960+
* while tracking the quotation level in the context.
1961+
*/
1962+
def typedQuote(tree: untpd.Quote, pt: Type)(implicit ctx: Context): Tree = track("typedQuote") {
1963+
if (tree.expr.isType)
1964+
typedTypeApply(untpd.TypeApply(untpd.ref(defn.QuotedType_applyR), List(tree.expr)), pt)(TreeMapWithStages.quoteContext).withSpan(tree.span)
1965+
else
1966+
typedApply(untpd.Apply(untpd.ref(defn.QuotedExpr_applyR), tree.expr), pt)(TreeMapWithStages.quoteContext).withSpan(tree.span)
1967+
}
1968+
19261969
/** Retrieve symbol attached to given tree */
19271970
protected def retrieveSym(tree: untpd.Tree)(implicit ctx: Context): Symbol = tree.removeAttachment(SymOfTree) match {
19281971
case Some(sym) =>
@@ -2015,6 +2058,7 @@ class Typer extends Namer
20152058
case tree: untpd.InfixOp if ctx.mode.isExpr => typedInfixOp(tree, pt)
20162059
case tree @ untpd.PostfixOp(qual, Ident(nme.WILDCARD)) => typedAsFunction(tree, pt)
20172060
case untpd.EmptyTree => tpd.EmptyTree
2061+
case tree: untpd.Quote => typedQuote(tree, pt)
20182062
case _ => typedUnadapted(desugar(tree), pt, locked)
20192063
}
20202064

tests/neg/quote-this-b.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import scala.quoted._
2+
3+
class Foo {
4+
inline def k(): Unit = ~Foo.impl[Any](this) // error
5+
inline def l(that: Foo): Unit = ~Foo.impl[Any](that) // error
6+
}
7+
8+
object Foo {
9+
def impl[T](x: Any): Expr[Unit] = '()
10+
}

tests/neg/quote-this.scala

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@ class Foo {
1919
'(that) // error
2020
})
2121

22-
inline def k(): Unit = ~Foo.impl[Any](this) // error
23-
inline def l(that: Foo): Unit = ~Foo.impl[Any](that) // error
24-
2522
}
2623

2724
object Foo {

tests/pos/quote-1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ object Test {
1111
f('{ true })('[Boolean])
1212

1313
def g(es: Expr[String], t: Type[String]) =
14-
f('{ (~es + "!") :: Nil })('[List[~t]])
14+
f('{ (~es + "!") :: Nil })('[List[t.unary_~]])
1515
}
1616

0 commit comments

Comments
 (0)