Skip to content

Commit 572a824

Browse files
committed
fix #10122: check parent types of references and types of parameters
1 parent 9ec34f8 commit 572a824

File tree

3 files changed

+63
-12
lines changed

3 files changed

+63
-12
lines changed

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

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -550,15 +550,41 @@ object Erasure {
550550
if (!ctx.mode.is(Mode.Type)) {
551551
if (isErased(tree))
552552
report.error(em"${tree.symbol} is declared as erased, but is in fact used", tree.srcPos)
553-
tree.symbol.getAnnotation(defn.CompileTimeOnlyAnnot) match {
554-
case Some(annot) =>
555-
def defaultMsg =
556-
i"""Reference to ${tree.symbol.showLocated} should not have survived,
557-
|it should have been processed and eliminated during expansion of an enclosing macro or term erasure."""
558-
val message = annot.argumentConstant(0).fold(defaultMsg)(_.stringValue)
559-
report.error(message, tree.srcPos)
560-
case _ => // OK
561-
}
553+
554+
def parentSyms(tpe: Type): LazyList[Symbol] =
555+
val ref = tpe.widen.finalResultType
556+
ref.classSymbol #:: ref.parents.to(LazyList).flatMap(parentSyms)
557+
558+
def checkTree(tree: Tree, pos: util.SrcPos, toCheck: LazyList[Symbol]): Boolean =
559+
toCheck.exists { sym =>
560+
sym.getAnnotation(defn.CompileTimeOnlyAnnot) match {
561+
case Some(annot) =>
562+
def defaultMsg =
563+
i"""Reference to ${tree.symbol.showLocated} should not have survived,
564+
|it should have been processed and eliminated during expansion of an enclosing macro or term erasure."""
565+
val message = annot.argumentConstant(0).fold(defaultMsg)(_.stringValue)
566+
report.error(message, pos)
567+
true
568+
case _ => // OK
569+
false
570+
}
571+
}
572+
573+
tree match
574+
case ddef: DefDef =>
575+
for
576+
vparams <- ddef.vparamss
577+
vparam <- vparams
578+
do
579+
checkTree(vparam, vparam.tpt.srcPos, parentSyms(vparam.tpt.tpe))
580+
checkTree(ddef, ddef.tpt.srcPos, parentSyms(ddef.tpt.tpe))
581+
582+
case vdef: ValDef => checkTree(vdef, vdef.tpt.srcPos, parentSyms(vdef.tpt.tpe))
583+
584+
case tree =>
585+
// in the other branches we avoid checking the symbol itself
586+
// in-case it is annotated for downstream members
587+
checkTree(tree, tree.srcPos, tree.symbol #:: parentSyms(tree.tpe))
562588
}
563589
tree
564590
}
@@ -844,8 +870,8 @@ object Erasure {
844870
override def typedValDef(vdef: untpd.ValDef, sym: Symbol)(using Context): Tree =
845871
if (sym.isEffectivelyErased) erasedDef(sym)
846872
else
847-
super.typedValDef(untpd.cpy.ValDef(vdef)(
848-
tpt = untpd.TypedSplice(TypeTree(sym.info).withSpan(vdef.tpt.span))), sym)
873+
checkNotErased(super.typedValDef(untpd.cpy.ValDef(vdef)(
874+
tpt = untpd.TypedSplice(TypeTree(sym.info).withSpan(vdef.tpt.span))), sym))
849875

850876
/** Besides normal typing, this function also compacts anonymous functions
851877
* with more than `MaxImplementedFunctionArity` parameters to use a single
@@ -889,7 +915,7 @@ object Erasure {
889915
vparamss = vparams :: Nil,
890916
tpt = untpd.TypedSplice(TypeTree(restpe).withSpan(ddef.tpt.span)),
891917
rhs = rhs1)
892-
super.typedDefDef(ddef1, sym)
918+
checkNotErased(super.typedDefDef(ddef1, sym))
893919
end typedDefDef
894920

895921
/** The outer parameter definition of a constructor if it needs one */

tests/neg/i10122.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import scala.annotation.compileTimeOnly
2+
3+
@compileTimeOnly("FooBar can not be used as an expression") trait FooBar
4+
5+
object foo extends FooBar // error
6+
7+
val fooAnon = new FooBar {} // error // error
8+
val fooRef1: FooBar = ??? // error
9+
def fooRef2: FooBar = ??? // error
10+
def useFoo(foo: FooBar): foo.type = foo // error // error // error
11+
val bar = fooRef2 // error
12+
13+
@compileTimeOnly("baz can not be used as an expression") val baz = 23
14+
val qux = baz // error
15+
16+
@compileTimeOnly("quux can not be used as an expression") def quux = 47
17+
val quxx = quux // error

tests/neg/i9825.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
object Module {
2+
@deprecated("Module.Foo is deprecated")
3+
type Foo[+A] = scala.List[A]
4+
}
5+
6+
object Test {
7+
val m: Module.Foo[String] = List("wow")
8+
}

0 commit comments

Comments
 (0)