Skip to content

Commit a5a3127

Browse files
committed
Fix #7519: Check PCP of constructor calls on the type
Detect when a a reference to a constructor is a static path. Also fix `isTerm` and `isType` on `Hole`. We do not pickle this extra info as when we unpickle it we already know if it will be a type or a term.
1 parent 3cb93f3 commit a5a3127

File tree

6 files changed

+29
-10
lines changed

6 files changed

+29
-10
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,8 @@ class TreeTypeMap(
121121
val bind1 = tmap.transformSub(bind)
122122
val expr1 = tmap.transform(expr)
123123
cpy.Labeled(labeled)(bind1, expr1)
124-
case Hole(n, args) =>
125-
Hole(n, args.mapConserve(transform)).withSpan(tree.span).withType(mapType(tree.tpe))
124+
case Hole(isTermHole, n, args) =>
125+
Hole(isTermHole, n, args.mapConserve(transform)).withSpan(tree.span).withType(mapType(tree.tpe))
126126
case tree1 =>
127127
super.transform(tree1)
128128
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1458,7 +1458,7 @@ object Trees {
14581458
this(this(x, arg), annot)
14591459
case Thicket(ts) =>
14601460
this(x, ts)
1461-
case Hole(_, args) =>
1461+
case Hole(_, _, args) =>
14621462
this(x, args)
14631463
case _ =>
14641464
foldMoreCases(x, tree)

compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ object TreePickler {
2121

2222
val sectionName = "ASTs"
2323

24-
case class Hole(idx: Int, args: List[tpd.Tree])(implicit @constructorOnly src: SourceFile) extends tpd.Tree {
24+
case class Hole(isTermHole: Boolean, idx: Int, args: List[tpd.Tree])(implicit @constructorOnly src: SourceFile) extends tpd.Tree {
25+
override def isTerm: Boolean = isTermHole
26+
override def isType: Boolean = !isTermHole
2527
override def fallbackToText(printer: Printer): Text =
2628
s"[[$idx|" ~~ printer.toTextGlobal(args, ", ") ~~ "]]"
2729
}
@@ -579,7 +581,7 @@ class TreePickler(pickler: TastyPickler) {
579581
pickleTree(lo);
580582
if (hi ne lo) pickleTree(hi)
581583
}
582-
case Hole(idx, args) =>
584+
case Hole(_, idx, args) =>
583585
writeByte(HOLE)
584586
withLength {
585587
writeNat(idx)

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import dotty.tools.dotc.core.NameKinds._
1313
import dotty.tools.dotc.core.StagingContext._
1414
import dotty.tools.dotc.core.StdNames._
1515
import dotty.tools.dotc.core.Symbols._
16-
import dotty.tools.dotc.core.tasty.TreePickler.Hole
1716
import dotty.tools.dotc.core.Types._
1817
import dotty.tools.dotc.util.SourcePosition
1918
import dotty.tools.dotc.util.Spans._
@@ -167,7 +166,12 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
167166
case tp1: SkolemType => isStaticPathOK(tp1.info)
168167
case _ => false
169168

170-
if (!sym.exists || levelOK(sym) || isStaticPathOK(tp))
169+
/* Is a reference to an `<init>` method on a class with a static path */
170+
def isStaticNew(tp1: Type): Boolean = tp1 match
171+
case tp1: TermRef => tp1.symbol.isConstructor && isStaticPathOK(tp1.prefix)
172+
case _ => false
173+
174+
if (!sym.exists || levelOK(sym) || isStaticPathOK(tp) || isStaticNew(tp))
171175
None
172176
else if (!sym.isStaticOwner && !isClassRef)
173177
tryHeal(sym, tp, pos)

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ class ReifyQuotes extends MacroTransform {
263263
assert(level == 1, "unexpected top splice outside quote")
264264
val (body1, quotes) = nested(isQuote = false).splitSplice(body)(spliceContext)
265265
val tpe = outer.embedded.getHoleType(body, splice)
266-
val hole = makeHole(body1, quotes, tpe).withSpan(splice.span)
266+
val hole = makeHole(splice.isTerm, body1, quotes, tpe).withSpan(splice.span)
267267
// We do not place add the inline marker for trees that where lifted as they come from the same file as their
268268
// enclosing quote. Any intemediate splice will add it's own Inlined node and cancel it before splicig the lifted tree.
269269
// Note that lifted trees are not necessarily expressions and that Inlined nodes are expected to be expressions.
@@ -378,9 +378,9 @@ class ReifyQuotes extends MacroTransform {
378378
/** Register `body` as an `embedded` quote or splice
379379
* and return a hole with `splices` as arguments and the given type `tpe`.
380380
*/
381-
private def makeHole(body: Tree, splices: List[Tree], tpe: Type)(implicit ctx: Context): Hole = {
381+
private def makeHole(isTermHole: Boolean, body: Tree, splices: List[Tree], tpe: Type)(implicit ctx: Context): Hole = {
382382
val idx = embedded.addTree(body, NoSymbol)
383-
Hole(idx, splices).withType(tpe).asInstanceOf[Hole]
383+
Hole(isTermHole, idx, splices).withType(tpe).asInstanceOf[Hole]
384384
}
385385

386386
override def transform(tree: Tree)(implicit ctx: Context): Tree =

tests/pos/i7519.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import scala.quoted._
2+
import scala.annotation.StaticAnnotation
3+
4+
object Test {
5+
class Annot extends StaticAnnotation
6+
7+
class Quoted[T]
8+
9+
inline def quote[T]: Quoted[T] = ${ quoteImpl[T] }
10+
def quoteImpl[T: Type](given qctx: QuoteContext): Expr[Quoted[T]] = '{
11+
new Quoted[T @Annot]
12+
}
13+
}

0 commit comments

Comments
 (0)