diff --git a/compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala b/compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala index 4c79a36b6abf..9aebea9bd594 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala @@ -121,8 +121,8 @@ class TreeTypeMap( val bind1 = tmap.transformSub(bind) val expr1 = tmap.transform(expr) cpy.Labeled(labeled)(bind1, expr1) - case Hole(n, args) => - Hole(n, args.mapConserve(transform)).withSpan(tree.span).withType(mapType(tree.tpe)) + case Hole(isTermHole, n, args) => + Hole(isTermHole, n, args.mapConserve(transform)).withSpan(tree.span).withType(mapType(tree.tpe)) case tree1 => super.transform(tree1) } diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 6e3a02fe86e3..38914097cc6f 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -1458,7 +1458,7 @@ object Trees { this(this(x, arg), annot) case Thicket(ts) => this(x, ts) - case Hole(_, args) => + case Hole(_, _, args) => this(x, args) case _ => foldMoreCases(x, tree) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index feb96a4929b0..19044baac2d5 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -21,7 +21,9 @@ object TreePickler { val sectionName = "ASTs" - case class Hole(idx: Int, args: List[tpd.Tree])(implicit @constructorOnly src: SourceFile) extends tpd.Tree { + case class Hole(isTermHole: Boolean, idx: Int, args: List[tpd.Tree])(implicit @constructorOnly src: SourceFile) extends tpd.Tree { + override def isTerm: Boolean = isTermHole + override def isType: Boolean = !isTermHole override def fallbackToText(printer: Printer): Text = s"[[$idx|" ~~ printer.toTextGlobal(args, ", ") ~~ "]]" } @@ -579,7 +581,7 @@ class TreePickler(pickler: TastyPickler) { pickleTree(lo); if (hi ne lo) pickleTree(hi) } - case Hole(idx, args) => + case Hole(_, idx, args) => writeByte(HOLE) withLength { writeNat(idx) diff --git a/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala b/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala index 711ac60daf90..c976599c7f19 100644 --- a/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala +++ b/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala @@ -13,7 +13,6 @@ import dotty.tools.dotc.core.NameKinds._ import dotty.tools.dotc.core.StagingContext._ import dotty.tools.dotc.core.StdNames._ import dotty.tools.dotc.core.Symbols._ -import dotty.tools.dotc.core.tasty.TreePickler.Hole import dotty.tools.dotc.core.Types._ import dotty.tools.dotc.util.SourcePosition import dotty.tools.dotc.util.Spans._ @@ -137,6 +136,8 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages( case tp: ThisType => assert(checkSymLevel(tp.cls, tp, pos).isEmpty) mapOver(tp) + case tp: AnnotatedType => + derivedAnnotatedType(tp, apply(tp.parent), tp.annot) case _ => mapOver(tp) } @@ -167,7 +168,12 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages( case tp1: SkolemType => isStaticPathOK(tp1.info) case _ => false - if (!sym.exists || levelOK(sym) || isStaticPathOK(tp)) + /* Is a reference to an `` method on a class with a static path */ + def isStaticNew(tp1: Type): Boolean = tp1 match + case tp1: TermRef => tp1.symbol.isConstructor && isStaticPathOK(tp1.prefix) + case _ => false + + if (!sym.exists || levelOK(sym) || isStaticPathOK(tp) || isStaticNew(tp)) None else if (!sym.isStaticOwner && !isClassRef) tryHeal(sym, tp, pos) diff --git a/compiler/src/dotty/tools/dotc/transform/Pickler.scala b/compiler/src/dotty/tools/dotc/transform/Pickler.scala index 21e748ec594e..4b0b77205936 100644 --- a/compiler/src/dotty/tools/dotc/transform/Pickler.scala +++ b/compiler/src/dotty/tools/dotc/transform/Pickler.scala @@ -78,7 +78,7 @@ class Pickler extends Phase { pickled.iterator.grouped(10).toList.zipWithIndex.map { case (row, i) => s"${i}0: ${row.mkString(" ")}" } - + // println(i"rawBytes = \n$rawBytes%\n%") // DEBUG if (pickling ne noPrinter) { println(i"**** pickled info of $cls") diff --git a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala index ceeff4f42ddb..b7c658c51ef6 100644 --- a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala @@ -157,6 +157,8 @@ class ReifyQuotes extends MacroTransform { val tagDef = tagDefCache.getOrElseUpdate(prefix.symbol, mkTagSymbolAndAssignType(prefix)) tagDef.symbol.typeRef } + case AnnotatedType(parent, _) => + apply(parent) // Only keep the Annotated tree case _ => mapOver(tp) } @@ -263,7 +265,7 @@ class ReifyQuotes extends MacroTransform { assert(level == 1, "unexpected top splice outside quote") val (body1, quotes) = nested(isQuote = false).splitSplice(body)(spliceContext) val tpe = outer.embedded.getHoleType(body, splice) - val hole = makeHole(body1, quotes, tpe).withSpan(splice.span) + val hole = makeHole(splice.isTerm, body1, quotes, tpe).withSpan(splice.span) // We do not place add the inline marker for trees that where lifted as they come from the same file as their // enclosing quote. Any intemediate splice will add it's own Inlined node and cancel it before splicig the lifted tree. // Note that lifted trees are not necessarily expressions and that Inlined nodes are expected to be expressions. @@ -378,9 +380,9 @@ class ReifyQuotes extends MacroTransform { /** Register `body` as an `embedded` quote or splice * and return a hole with `splices` as arguments and the given type `tpe`. */ - private def makeHole(body: Tree, splices: List[Tree], tpe: Type)(implicit ctx: Context): Hole = { + private def makeHole(isTermHole: Boolean, body: Tree, splices: List[Tree], tpe: Type)(implicit ctx: Context): Hole = { val idx = embedded.addTree(body, NoSymbol) - Hole(idx, splices).withType(tpe).asInstanceOf[Hole] + Hole(isTermHole, idx, splices).withType(tpe).asInstanceOf[Hole] } override def transform(tree: Tree)(implicit ctx: Context): Tree = diff --git a/tests/pos/i7519.scala b/tests/pos/i7519.scala new file mode 100644 index 000000000000..d05787834b3a --- /dev/null +++ b/tests/pos/i7519.scala @@ -0,0 +1,13 @@ +import scala.quoted._ +import scala.annotation.StaticAnnotation + +object Test { + class Annot extends StaticAnnotation + + class Quoted[T] + + inline def quote[T]: Quoted[T] = ${ quoteImpl[T] } + def quoteImpl[T: Type](given qctx: QuoteContext): Expr[Quoted[T]] = '{ + new Quoted[T @Annot] + } +} diff --git a/tests/pos/i7519b.scala b/tests/pos/i7519b.scala new file mode 100644 index 000000000000..f47c3ba0b8b1 --- /dev/null +++ b/tests/pos/i7519b.scala @@ -0,0 +1,13 @@ +import scala.quoted._ +import scala.annotation.StaticAnnotation + +class Annot(in: Int) extends StaticAnnotation + +class Quoted[T] + +inline def quote[T]: Quoted[T] = ${ quoteImpl[T] } + +def quoteImpl[T: Type](given qctx: QuoteContext): Expr[Quoted[T]] = { + val value: Expr[Int] = '{ 42 } + '{ new Quoted[T @Annot($value)] } +} diff --git a/tests/run-macros/i7519c.check b/tests/run-macros/i7519c.check new file mode 100644 index 000000000000..0d41584485bd --- /dev/null +++ b/tests/run-macros/i7519c.check @@ -0,0 +1 @@ +new Quoted[scala.Int @Annot(42)]() diff --git a/tests/run-macros/i7519c/Macro_1.scala b/tests/run-macros/i7519c/Macro_1.scala new file mode 100644 index 000000000000..586a6d39006e --- /dev/null +++ b/tests/run-macros/i7519c/Macro_1.scala @@ -0,0 +1,13 @@ +import scala.quoted._ +import scala.annotation.StaticAnnotation + +class Annot(in: Int) extends StaticAnnotation + +class Quoted[T] + +inline def quote[T]: String = ${ quoteImpl[T] } + +def quoteImpl[T: Type](given qctx: QuoteContext): Expr[String] = { + val value: Expr[Int] = '{ 42 } + Expr(('{ new Quoted[T @Annot($value)] }).show) +} diff --git a/tests/run-macros/i7519c/Test_2.scala b/tests/run-macros/i7519c/Test_2.scala new file mode 100644 index 000000000000..9e77d5871ebe --- /dev/null +++ b/tests/run-macros/i7519c/Test_2.scala @@ -0,0 +1,5 @@ +object Test { + def main(args: Array[String]): Unit = { + println(quote[Int]) + } +}