Skip to content

Commit 4aa3937

Browse files
committed
wip
1 parent 805a9c3 commit 4aa3937

File tree

2 files changed

+88
-55
lines changed

2 files changed

+88
-55
lines changed

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

Lines changed: 79 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,6 @@ class Staging extends MacroTransformWithImplicits {
127127
*/
128128
val importedTags = new mutable.LinkedHashMap[TypeRef, Tree]()
129129

130-
131130
/** A stack of entered symbols, to be unwound after scope exit */
132131
var enteredSyms: List[Symbol] = Nil
133132

@@ -267,68 +266,80 @@ class Staging extends MacroTransformWithImplicits {
267266
* @return Some(msg) if unsuccessful where `msg` is a potentially empty error message
268267
* to be added to the "inconsistent phase" message.
269268
*/
270-
def tryHeal(tp: Type, pos: SourcePosition)(implicit ctx: Context): Option[String] = tp match {
271-
case tp: TypeRef =>
272-
if (level == -1) {
273-
assert(ctx.inInlineMethod)
274-
None
275-
} else {
276-
val reqType = defn.QuotedTypeType.appliedTo(tp)
277-
val tag = ctx.typer.inferImplicitArg(reqType, pos.span)
278-
tag.tpe match {
279-
case fail: SearchFailureType =>
280-
Some(i"""
281-
|
282-
| The access would be accepted with the right type tag, but
283-
| ${ctx.typer.missingArgMsg(tag, reqType, "")}""")
284-
case _ =>
285-
importedTags(tp) = nested(isQuote = false).transform(tag)
286-
None
269+
def tryHeal(sym: Symbol, tp: Type, pos: SourcePosition)(implicit ctx: Context): Option[Tree] = {
270+
def levelError(errMsg: String) = {
271+
def symStr =
272+
if (!tp.isInstanceOf[ThisType]) sym.show
273+
else if (sym.is(ModuleClass)) sym.sourceModule.show
274+
else i"${sym.name}.this"
275+
ctx.error(
276+
em"""access to $symStr from wrong staging level:
277+
| - the definition is at level ${levelOf.getOrElse(sym, 0)},
278+
| - but the access is at level $level.$errMsg""", pos)
279+
None
280+
}
281+
tp match {
282+
case tp: TypeRef =>
283+
if (level == -1) {
284+
assert(ctx.inInlineMethod)
285+
None
286+
} else {
287+
val reqType = defn.QuotedTypeType.appliedTo(tp)
288+
val tag = ctx.typer.inferImplicitArg(reqType, pos.span)
289+
tag.tpe match {
290+
case fail: SearchFailureType =>
291+
levelError(i"""
292+
|
293+
| The access would be accepted with the right type tag, but
294+
| ${ctx.typer.missingArgMsg(tag, reqType, "")}""")
295+
case _ =>
296+
importedTags(tp) = nested(isQuote = false).transform(tag) // TODO remove me
297+
Some(nested(isQuote = false).transform(tag).select(tpnme.UNARY_~)) // TODO remove the transform?
298+
}
287299
}
288-
}
289-
case _ =>
290-
Some("")
300+
case _ =>
301+
levelError("")
302+
}
291303
}
292304

293305
/** Check reference to `sym` for phase consistency, where `tp` is the underlying type
294306
* by which we refer to `sym`.
295307
*/
296-
def check(sym: Symbol, tp: Type, pos: SourcePosition)(implicit ctx: Context): Unit = {
308+
def check(sym: Symbol, tp: Type, pos: SourcePosition)(implicit ctx: Context): Option[Tree] = {
297309
val isThis = tp.isInstanceOf[ThisType]
298-
def symStr =
299-
if (!isThis) sym.show
300-
else if (sym.is(ModuleClass)) sym.sourceModule.show
301-
else i"${sym.name}.this"
302310
if (!isThis && sym.maybeOwner.isType && !sym.is(Param))
303311
check(sym.owner, sym.owner.thisType, pos)
304312
else if (sym.exists && !sym.isStaticOwner && !levelOK(sym))
305-
for (errMsg <- tryHeal(tp, pos))
306-
ctx.error(em"""access to $symStr from wrong staging level:
307-
| - the definition is at level ${levelOf.getOrElse(sym, 0)},
308-
| - but the access is at level $level.$errMsg""", pos)
313+
tryHeal(sym, tp, pos)
314+
else
315+
None
309316
}
310317

311318
/** Check all named types and this-types in a given type for phase consistency. */
312-
def checkType(pos: SourcePosition)(implicit ctx: Context): TypeAccumulator[Unit] = new TypeAccumulator[Unit] {
313-
def apply(acc: Unit, tp: Type): Unit = reporting.trace(i"check type level $tp at $level") {
319+
def checkType(pos: SourcePosition)(implicit ctx: Context): TypeMap = new TypeMap {
320+
def apply(tp: Type): Type = reporting.trace(i"check type level $tp at $level") {
314321
tp match {
315322
case tp: TypeRef if tp.symbol.isSplice =>
316323
if (inQuote) {
317-
outer.checkType(pos).foldOver(acc, tp)
324+
// TODO add level to checkType TypeMap and avoid accessing the outer one?
325+
outer.checkType(pos).mapOver(tp)
318326
}
319327
else {
320328
if (tp.isTerm) ctx.error(i"splice outside quotes", pos)
321329
tp
322330
}
323331
case tp: NamedType =>
324-
check(tp.symbol, tp, tp.symbol.sourcePos)
325-
if (!tp.symbol.is(Param))
326-
foldOver(acc, tp)
332+
check(tp.symbol, tp, tp.symbol.sourcePos) match {
333+
case Some(tpRef) => tpRef.tpe
334+
case _ =>
335+
if (tp.symbol.is(Param)) tp
336+
else mapOver(tp)
337+
}
327338
case tp: ThisType =>
328-
check(tp.cls, tp, tp.cls.sourcePos)
329-
foldOver(acc, tp)
339+
assert(check(tp.cls, tp, tp.cls.sourcePos).isEmpty)
340+
mapOver(tp)
330341
case _ =>
331-
foldOver(acc, tp)
342+
mapOver(tp)
332343
}
333344
}
334345
}
@@ -348,19 +359,32 @@ class Staging extends MacroTransformWithImplicits {
348359
*/
349360
private def checkLevel(tree: Tree)(implicit ctx: Context): Tree = {
350361
tree match {
351-
case (_: Ident) | (_: This) =>
352-
check(tree.symbol, tree.tpe, tree.sourcePos)
362+
case _: This =>
363+
assert(check(tree.symbol, tree.tpe, tree.sourcePos).isEmpty)
364+
tree
365+
case _: Ident =>
366+
check(tree.symbol, tree.tpe, tree.sourcePos) match {
367+
case Some(tpRef) => tpRef
368+
case _ => tree
369+
}
353370
case (_: UnApply) | (_: TypeTree) =>
354-
checkType(tree.sourcePos).apply((), tree.tpe)
371+
checkType(tree.sourcePos).apply(tree.tpe)
372+
tree
355373
case Select(qual, OuterSelectName(_, levels)) =>
356-
checkType(tree.sourcePos).apply((), tree.tpe.widen)
374+
checkType(tree.sourcePos).apply(tree.tpe.widen)
375+
tree
357376
case _: Bind =>
358-
checkType(tree.sourcePos).apply((), tree.symbol.info)
377+
checkType(tree.sourcePos).apply(tree.symbol.info)
378+
tree
359379
case _: Template =>
360-
checkType(tree.sourcePos).apply((), tree.symbol.owner.asClass.givenSelfType)
380+
checkType(tree.sourcePos).apply(tree.symbol.owner.asClass.givenSelfType)
381+
tree
382+
case tree: Typed =>
383+
val tp = checkType(tree.sourcePos).apply(tree.tpe)
384+
tree.withType(tp)
361385
case _ =>
386+
tree
362387
}
363-
tree
364388
}
365389

366390
/** Split `body` into a core and a list of embedded splices.
@@ -424,7 +448,8 @@ class Staging extends MacroTransformWithImplicits {
424448
/** Transform `tree` followed by `addTags` transform. */
425449
private def transformAndAddTags(tree: Tree)(implicit ctx: Context): Tree = {
426450
assert(inQuote)
427-
addTags(transform(tree))
451+
// addTags(transform(tree))
452+
transform(tree)
428453
}
429454

430455
override def transform(tree: Tree)(implicit ctx: Context): Tree =
@@ -449,11 +474,11 @@ class Staging extends MacroTransformWithImplicits {
449474
if (tree.isType || level == 0) splice(tree)
450475
else {
451476
// TODO add comment '{ ~(...: T) } --> '{ ~(...: T).asInstanceOf[T] } --> '{ ~(...: T).asInstanceOf[~t] }
452-
val tp = tree.tpe.widenTermRefExpr
453-
checkType(tree.sourcePos).apply((), tp)
477+
val tp = checkType(tree.sourcePos).apply(tree.tpe.widenTermRefExpr)
454478
splice(tree).asInstance(tp).withSpan(tree.span)
455479
}
456480
}
481+
//TODO remove this case?
457482
case tree: RefTree if tree.symbol.is(Inline) && tree.symbol.is(Param) =>
458483
tree
459484
case Block(stats, _) =>
@@ -495,18 +520,17 @@ class Staging extends MacroTransformWithImplicits {
495520
case tree: DefDef if tree.symbol.is(Macro) && level > 0 =>
496521
mapOverTree(enteredSyms)
497522
EmptyTree
523+
case tree: ValDef =>
524+
markDef(tree)
525+
val tree1 @ ValDef(_, tpt, _) = checkLevel(mapOverTree(enteredSyms))
526+
tree1.symbol.info = tpt.tpe // TODO transform in a cleaner way
527+
tree1
498528
case _ =>
499529
markDef(tree)
500530
checkLevel(mapOverTree(enteredSyms))
501531
}
502532
}
503533

504-
private def liftList(list: List[Tree], tpe: Type)(implicit ctx: Context): Tree = {
505-
list.foldRight[Tree](ref(defn.NilModule)) { (x, acc) =>
506-
acc.select("::".toTermName).appliedToType(tpe).appliedTo(x)
507-
}
508-
}
509-
510534
/** InlineSplice is used to detect cases where the expansion
511535
* consists of a (possibly multiple & nested) block or a sole expression.
512536
*/

tests/pos/quote-liftable-list.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import scala.quoted._
2+
3+
object Test {
4+
5+
implicit def ListIsLiftable[T: Liftable: Type]: Liftable[List[T]] = new {
6+
def toExpr(xs: List[T]): Expr[List[T]] = '(Nil: List[T])
7+
}
8+
9+
}

0 commit comments

Comments
 (0)