Skip to content

Commit f7c5620

Browse files
committed
WIP
1 parent 3350891 commit f7c5620

File tree

2 files changed

+39
-25
lines changed

2 files changed

+39
-25
lines changed

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,6 +1113,9 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
11131113
/** A key to be used in a context property that tracks enclosing inlined calls */
11141114
private val InlinedCalls = new Property.Key[List[Tree]]
11151115

1116+
/** A key to be used in a context property that tracks the quoteation level */
1117+
private val QuotationLevel = new Property.Key[Int]
1118+
11161119
/** Record an enclosing inlined call.
11171120
* EmptyTree calls (for parameters) cancel the next-enclosing call in the list instead of being added to it.
11181121
* We assume parameters are never nested inside parameters.
@@ -1134,6 +1137,18 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
11341137
def enclosingInlineds(implicit ctx: Context): List[Tree] =
11351138
ctx.property(InlinedCalls).getOrElse(Nil)
11361139

1140+
/** All enclosing calls that are currently inlined, from innermost to outermost. */
1141+
def quotationLevel(implicit ctx: Context): Int =
1142+
ctx.property(QuotationLevel).getOrElse(0)
1143+
1144+
/** Context with an incremented quotation level. */
1145+
def quoteContext(implicit ctx: Context): Context =
1146+
ctx.fresh.setProperty(QuotationLevel, quotationLevel + 1)
1147+
1148+
/** Context with a decremented quotation level. */
1149+
def spliceContext(implicit ctx: Context): Context =
1150+
ctx.fresh.setProperty(QuotationLevel, quotationLevel - 1)
1151+
11371152
/** The source file where the symbol of the `inline` method referred to by `call`
11381153
* is defined
11391154
*/

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

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class Staging extends MacroTransformWithImplicits {
9393
if (ctx.compilationUnit.needsStaging) super.run
9494

9595
protected def newTransformer(implicit ctx: Context): Transformer =
96-
new Reifier(0, new LevelInfo)
96+
new Reifier(new LevelInfo)
9797

9898
private class LevelInfo {
9999
/** A map from locally defined symbols to the staging levels of their definitions */
@@ -106,14 +106,13 @@ class Staging extends MacroTransformWithImplicits {
106106
* and `l == -1` is code inside a top level splice (in an inline method).
107107
* @param levels a stacked map from symbols to the levels in which they were defined
108108
*/
109-
private class Reifier(val level: Int, levels: LevelInfo)
109+
private class Reifier(levels: LevelInfo)
110110
extends ImplicitsTransformer {
111111
import levels._
112-
assert(level >= -1)
113112

114113
/** A nested reifier for a quote (if `isQuote = true`) or a splice (if not) */
115114
def nested(isQuote: Boolean)(implicit ctx: Context): Reifier = {
116-
new Reifier(if (isQuote) level + 1 else level - 1, levels)
115+
new Reifier(levels)
117116
}
118117

119118
/** A stack of entered symbols, to be unwound after scope exit */
@@ -124,7 +123,7 @@ class Staging extends MacroTransformWithImplicits {
124123
case tree: DefTree =>
125124
val sym = tree.symbol
126125
if ((sym.isClass || !sym.maybeOwner.isType) && !levelOf.contains(sym)) {
127-
levelOf(sym) = level
126+
levelOf(sym) = quotationLevel
128127
enteredSyms = sym :: enteredSyms
129128
}
130129
case _ =>
@@ -137,8 +136,8 @@ class Staging extends MacroTransformWithImplicits {
137136
*/
138137
def levelOK(sym: Symbol)(implicit ctx: Context): Boolean = levelOf.get(sym) match {
139138
case Some(l) =>
140-
l == level ||
141-
level == -1 && (
139+
l == quotationLevel ||
140+
quotationLevel == -1 && (
142141
sym == defn.TastyReflection_macroContext ||
143142
// here we assume that Splicer.canBeSpliced was true before going to level -1,
144143
// this implies that all non-inline arguments are quoted and that the following two cases are checked
@@ -164,12 +163,12 @@ class Staging extends MacroTransformWithImplicits {
164163
ctx.error(
165164
em"""access to $symStr from wrong staging level:
166165
| - the definition is at level ${levelOf.getOrElse(sym, 0)},
167-
| - but the access is at level $level.$errMsg""", pos)
166+
| - but the access is at level $quotationLevel.$errMsg""", pos)
168167
None
169168
}
170169
tp match {
171170
case tp: TypeRef =>
172-
if (level == -1) {
171+
if (quotationLevel == -1) {
173172
assert(ctx.inInlineMethod)
174173
None
175174
} else {
@@ -205,7 +204,7 @@ class Staging extends MacroTransformWithImplicits {
205204

206205
/** Check all named types and this-types in a given type for phase consistency. */
207206
def checkType(pos: SourcePosition)(implicit ctx: Context): TypeMap = new TypeMap {
208-
def apply(tp: Type): Type = reporting.trace(i"check type level $tp at $level") {
207+
def apply(tp: Type): Type = reporting.trace(i"check type level $tp at $quotationLevel") {
209208
tp match {
210209
case tp: TypeRef if tp.symbol.isSplice =>
211210
if (tp.isTerm)
@@ -278,14 +277,14 @@ class Staging extends MacroTransformWithImplicits {
278277
*/
279278
private def quotation(body: Tree, quote: Tree)(implicit ctx: Context): Tree = {
280279
val isType = quote.symbol eq defn.QuotedType_apply
281-
if (level > 0) {
282-
val body1 = nested(isQuote = true).transform(body)
280+
if (quotationLevel > 0) {
281+
val body1 = nested(isQuote = true).transform(body)(quoteContext)
283282
// Keep quotes as trees to reduce pickled size and have a Expr.show without pickled quotes
284283
if (isType) ref(defn.QuotedType_apply).appliedToType(body1.tpe.widen)
285284
else ref(defn.QuotedExpr_apply).appliedToType(body1.tpe.widen).appliedTo(body1)
286285
} else {
287-
val body1 = nested(isQuote = true).transform(body)
288-
if (level == 0 && !ctx.inInlineMethod) {
286+
val body1 = nested(isQuote = true).transform(body)(quoteContext)
287+
if (quotationLevel == 0 && !ctx.inInlineMethod) {
289288
quote match {
290289
case quote: Apply => cpy.Apply(quote)(quote.fun, body1 :: Nil)
291290
case quote: TypeApply => cpy.TypeApply(quote)(quote.fun, body1 :: Nil)
@@ -303,24 +302,24 @@ class Staging extends MacroTransformWithImplicits {
303302
* are in the body of an inline method.
304303
*/
305304
private def splice(splice: Select)(implicit ctx: Context): Tree = {
306-
if (level >= 1) {
307-
val body1 = nested(isQuote = false).transform(splice.qualifier)
305+
if (quotationLevel >= 1) {
306+
val body1 = nested(isQuote = false).transform(splice.qualifier)(spliceContext)
308307
body1.select(splice.name)
309308
}
310-
else if (enclosingInlineds.nonEmpty) { // level 0 in an inlined call
309+
else if (enclosingInlineds.nonEmpty) { // quotationLevel 0 in an inlined call
311310
val spliceCtx = ctx.outer // drop the last `inlineContext`
312311
val pos: SourcePosition = spliceCtx.source.atSpan(enclosingInlineds.head.span)
313312
val evaluatedSplice = Splicer.splice(splice.qualifier, pos, macroClassLoader)(spliceCtx).withSpan(splice.span)
314313
if (ctx.reporter.hasErrors) splice else transform(evaluatedSplice)
315314
}
316-
else if (!ctx.owner.isInlineMethod) { // level 0 outside an inline method
315+
else if (!ctx.owner.isInlineMethod) { // quotationLevel 0 outside an inline method
317316
ctx.error(i"splice outside quotes or inline method", splice.sourcePos)
318317
splice
319318
}
320-
else if (Splicer.canBeSpliced(splice.qualifier)) { // level 0 inside an inline definition
321-
nested(isQuote = false).transform(splice.qualifier) // Just check PCP
319+
else if (Splicer.canBeSpliced(splice.qualifier)) { // quotationLevel 0 inside an inline definition
320+
nested(isQuote = false).transform(splice.qualifier)(spliceContext) // Just check PCP
322321
}
323-
else { // level 0 inside an inline definition
322+
else { // quotationLevel 0 inside an inline definition
324323
ctx.error(
325324
"Malformed macro call. The contents of the ~ must call a static method and arguments must be quoted or inline.".stripMargin,
326325
splice.sourcePos)
@@ -329,7 +328,7 @@ class Staging extends MacroTransformWithImplicits {
329328
}
330329

331330
override def transform(tree: Tree)(implicit ctx: Context): Tree =
332-
reporting.trace(i"reify $tree at $level", show = true) {
331+
reporting.trace(i"reify $tree at $quotationLevel", show = true) {
333332
def mapOverTree(lastEntered: List[Symbol]) =
334333
try super.transform(tree)
335334
finally
@@ -347,7 +346,7 @@ class Staging extends MacroTransformWithImplicits {
347346
tree.qualifier match {
348347
case Quoted(quotedTree) => transform(quotedTree) // ~('x) --> x
349348
case _ =>
350-
if (tree.isType || level == 0) splice(tree)
349+
if (tree.isType || quotationLevel == 0) splice(tree)
351350
else {
352351
// TODO add comment '{ ~(...: T) } --> '{ ~(...: T).asInstanceOf[T] } --> '{ ~(...: T).asInstanceOf[~t] }
353352
val tp = checkType(tree.sourcePos).apply(tree.tpe.widenTermRefExpr)
@@ -373,7 +372,7 @@ class Staging extends MacroTransformWithImplicits {
373372
mapOverTree(last)
374373
case _: Import =>
375374
tree
376-
case tree: DefDef if tree.symbol.is(Macro) && level == 0 =>
375+
case tree: DefDef if tree.symbol.is(Macro) && quotationLevel == 0 =>
377376
if (enclosingInlineds.nonEmpty)
378377
return EmptyTree // Already checked at definition site and already inlined
379378
markDef(tree)
@@ -393,7 +392,7 @@ class Staging extends MacroTransformWithImplicits {
393392
""".stripMargin, tree.rhs.sourcePos)
394393
tree
395394
}
396-
case tree: DefDef if tree.symbol.is(Macro) && level > 0 =>
395+
case tree: DefDef if tree.symbol.is(Macro) && quotationLevel > 0 =>
397396
mapOverTree(enteredSyms)
398397
EmptyTree
399398
case tree: ValDef =>

0 commit comments

Comments
 (0)