aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/transform/PostTyper.scala36
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala40
-rw-r--r--tests/neg/i997.scala2
3 files changed, 44 insertions, 34 deletions
diff --git a/src/dotty/tools/dotc/transform/PostTyper.scala b/src/dotty/tools/dotc/transform/PostTyper.scala
index b4b01d1f3..8c8eb0978 100644
--- a/src/dotty/tools/dotc/transform/PostTyper.scala
+++ b/src/dotty/tools/dotc/transform/PostTyper.scala
@@ -128,40 +128,8 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
annot.derivedAnnotation(transformAnnot(annot.tree))
private def transformMemberDef(tree: MemberDef)(implicit ctx: Context): Unit = {
- val sym = tree.symbol
- sym.transformAnnotations(transformAnnot)
- type Errors = List[(String, Position)]
- val notPrivate = new TypeAccumulator[Errors] {
- def boundary(sym: Symbol): Symbol =
- if (sym.is(Private)) sym.owner
- else if (sym.privateWithin.exists) sym.privateWithin
- else if (sym.is(Package)) sym
- else boundary(sym.owner)
- def apply(errors: Errors, tp: Type): Errors = tp match {
- case tp: NamedType =>
- val errors1 =
- if (tp.symbol.is(Private) &&
- !boundary(sym).isContainedIn(boundary(tp.symbol))) {
- //println(i"sym = $sym, ref = ${tp.symbol}, symb = ${boundary(sym)}, refb = ${boundary(tp.symbol)}")
- (d"non-private $sym refers to private ${tp.symbol}\n in its type signature ${sym.info}", tree.pos) :: errors
- }
- else foldOver(errors, tp)
- if ((errors1 ne errors) && tp.info.isAlias) {
- val errors2 = apply(errors, tp.info.bounds.hi)
- if (errors2 eq errors) errors2
- else errors1
- }
- else errors1
- case tp: ClassInfo =>
- (apply(errors, tp.prefix) /: tp.typeRef.parentsWithArgs)(apply)
- case _ =>
- foldOver(errors, tp)
- }
- }
- if (!sym.is(SyntheticOrPrivate) && sym.owner.isClass) {
- val errors = notPrivate(Nil, sym.info)
- errors.foreach { case (msg, pos) => ctx.errorOrMigrationWarning(msg, pos) }
- }
+ tree.symbol.transformAnnotations(transformAnnot)
+ Checking.checkNoPrivateLeaks(tree)
}
private def transformSelect(tree: Select, targs: List[Tree])(implicit ctx: Context): Tree = {
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
index 437902d05..64aac7d3b 100644
--- a/src/dotty/tools/dotc/typer/Checking.scala
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -312,6 +312,46 @@ object Checking {
checkNoConflict(Private, Protected)
checkNoConflict(Abstract, Override)
}
+
+ /** Check the type signature of the symbol `M` defined by `tree` does not refer
+ * to a private type or value which is invisible at a point where `M` is still
+ * visible. As an exception, we allow references to type aliases if the underlying
+ * type of the alias is not a leak. So type aliases are transparent as far as
+ * leak testing is concerned. See 997.scala for tests.
+ */
+ def checkNoPrivateLeaks(tree: MemberDef)(implicit ctx: Context): Unit = {
+ type Errors = List[(String, Position)]
+ val sym = tree.symbol
+ val notPrivate = new TypeAccumulator[Errors] {
+ def accessBoundary(sym: Symbol): Symbol =
+ if (sym.is(Private)) sym.owner
+ else if (sym.privateWithin.exists) sym.privateWithin
+ else if (sym.is(Package)) sym
+ else accessBoundary(sym.owner)
+ def apply(errors: Errors, tp: Type): Errors = tp match {
+ case tp: NamedType =>
+ val errors1 =
+ if (tp.symbol.is(Private) &&
+ !accessBoundary(sym).isContainedIn(tp.symbol.owner)) {
+ (d"non-private $sym refers to private ${tp.symbol}\n in its type signature ${sym.info}", tree.pos) :: errors
+ } else foldOver(errors, tp)
+ if ((errors1 ne errors) && tp.info.isAlias) {
+ // try to dealias to avoid a leak error
+ val errors2 = apply(errors, tp.info.bounds.hi)
+ if (errors2 eq errors) errors2
+ else errors1
+ } else errors1
+ case tp: ClassInfo =>
+ (apply(errors, tp.prefix) /: tp.typeRef.parentsWithArgs)(apply)
+ case _ =>
+ foldOver(errors, tp)
+ }
+ }
+ if (!sym.is(SyntheticOrPrivate) && sym.owner.isClass) {
+ val errors = notPrivate(Nil, sym.info)
+ errors.foreach { case (msg, pos) => ctx.errorOrMigrationWarning(msg, pos) }
+ }
+ }
}
trait Checking {
diff --git a/tests/neg/i997.scala b/tests/neg/i997.scala
index bfcf5637e..8a21661fb 100644
--- a/tests/neg/i997.scala
+++ b/tests/neg/i997.scala
@@ -1,9 +1,11 @@
class C {
private type T = E
+ private type Tok = D
private val p: C = new C
def f1(x: T): Unit = () // error
+ def f1(x: Tok): Unit = () // ok
def f2(x: p.D): Unit = () // error
val v1: T = ??? // error