Skip to content

Fix #7519: Check PCP of constructor calls on the type #7531

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 4 additions & 2 deletions compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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, ", ") ~~ "]]"
}
Expand Down Expand Up @@ -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)
Expand Down
10 changes: 8 additions & 2 deletions compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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._
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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 `<init>` 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)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/Pickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
8 changes: 5 additions & 3 deletions compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it mean it throws the annotation away? That will make it impossible to keep some annotations in types.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We throw away the annotation on the type but then recover it from the Annotated type tree while unpickling.
Maybe I should only do it if it contains a splice. In that case we would always have the tree.

case _ =>
mapOver(tp)
}
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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 =
Expand Down
13 changes: 13 additions & 0 deletions tests/pos/i7519.scala
Original file line number Diff line number Diff line change
@@ -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]
}
}
13 changes: 13 additions & 0 deletions tests/pos/i7519b.scala
Original file line number Diff line number Diff line change
@@ -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)] }
}
1 change: 1 addition & 0 deletions tests/run-macros/i7519c.check
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
new Quoted[scala.Int @Annot(42)]()
13 changes: 13 additions & 0 deletions tests/run-macros/i7519c/Macro_1.scala
Original file line number Diff line number Diff line change
@@ -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)
}
5 changes: 5 additions & 0 deletions tests/run-macros/i7519c/Test_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
object Test {
def main(args: Array[String]): Unit = {
println(quote[Int])
}
}