Skip to content

Commit 216c195

Browse files
committed
Have checkNotPrivate skip over private aliases.
CheckNotPrivate now avoids private aliases, so that types sat prepresentable in transformation phases. This does not solve the problem that private classes or abstract types might leak coming from Scala 2, but there is not really a good cure for that. We can reject them outright or allow them under language:Scala2 and hope for the best.
1 parent e68d684 commit 216c195

File tree

3 files changed

+47
-23
lines changed

3 files changed

+47
-23
lines changed

src/dotty/tools/dotc/transform/PostTyper.scala

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,13 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
131131
annot.derivedAnnotation(transformAnnot(annot.tree))
132132

133133
private def transformMemberDef(tree: MemberDef)(implicit ctx: Context): Unit = {
134-
tree.symbol.transformAnnotations(transformAnnot)
135-
Checking.checkNoPrivateLeaks(tree)
134+
val sym = tree.symbol
135+
sym.transformAnnotations(transformAnnot)
136+
if (!sym.is(SyntheticOrPrivate) && sym.owner.isClass) {
137+
val info1 = Checking.checkNoPrivateLeaks(sym, tree.pos)
138+
if (info1 ne sym.info)
139+
sym.copySymDenotation(info = info1).installAfter(thisTransformer)
140+
}
136141
}
137142

138143
private def transformSelect(tree: Select, targs: List[Tree])(implicit ctx: Context): Tree = {

src/dotty/tools/dotc/typer/Checking.scala

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -327,40 +327,53 @@ object Checking {
327327
* to a private type or value which is invisible at a point where `M` is still
328328
* visible. As an exception, we allow references to type aliases if the underlying
329329
* type of the alias is not a leak. So type aliases are transparent as far as
330-
* leak testing is concerned. See 997.scala for tests.
330+
* leak testing is concerned.
331+
* @return The `info` of `sym`, with problematic aliases expanded away.
332+
* See i997.scala for tests, i1130.scala for a case where it matters that we
333+
* transform leaky aliases away.
331334
*/
332-
def checkNoPrivateLeaks(tree: MemberDef)(implicit ctx: Context): Unit = {
333-
type Errors = List[(String, Position)]
334-
val sym = tree.symbol
335-
val notPrivate = new TypeAccumulator[Errors] {
335+
def checkNoPrivateLeaks(sym: Symbol, pos: Position)(implicit ctx: Context): Type = {
336+
class NotPrivate extends TypeMap {
337+
type Errors = List[(String, Position)]
338+
var errors: Errors = Nil
336339
def accessBoundary(sym: Symbol): Symbol =
337340
if (sym.is(Private)) sym.owner
338341
else if (sym.privateWithin.exists) sym.privateWithin
339342
else if (sym.is(Package)) sym
340343
else accessBoundary(sym.owner)
341-
def apply(errors: Errors, tp: Type): Errors = tp match {
344+
def apply(tp: Type): Type = tp match {
342345
case tp: NamedType =>
343-
val errors1 =
346+
val prevErrors = errors
347+
var tp1 =
344348
if (tp.symbol.is(Private) &&
345-
!accessBoundary(sym).isContainedIn(tp.symbol.owner)) {
346-
(d"non-private $sym refers to private ${tp.symbol}\n in its type signature ${sym.info}", tree.pos) :: errors
347-
} else foldOver(errors, tp)
348-
if ((errors1 ne errors) && tp.info.isAlias) {
349+
!accessBoundary(sym).isContainedIn(tp.symbol.owner)) {
350+
errors = (d"non-private $sym refers to private ${tp.symbol}\n in its type signature ${sym.info}",
351+
pos) :: errors
352+
tp
353+
}
354+
else mapOver(tp)
355+
if ((errors ne prevErrors) && tp.info.isAlias) {
349356
// try to dealias to avoid a leak error
350-
val errors2 = apply(errors, tp.info.bounds.hi)
351-
if (errors2 eq errors) errors2
352-
else errors1
353-
} else errors1
357+
val savedErrors = errors
358+
errors = prevErrors
359+
val tp2 = apply(tp.info.bounds.hi)
360+
if (errors eq prevErrors) tp1 = tp2
361+
else errors = savedErrors
362+
}
363+
tp1
354364
case tp: ClassInfo =>
355-
(apply(errors, tp.prefix) /: tp.parentsWithArgs)(apply)
365+
tp.derivedClassInfo(
366+
prefix = apply(tp.prefix),
367+
classParents = tp.parentsWithArgs.map(p =>
368+
apply(p).underlyingClassRef(refinementOK = false).asInstanceOf[TypeRef]))
356369
case _ =>
357-
foldOver(errors, tp)
370+
mapOver(tp)
358371
}
359372
}
360-
if (!sym.is(SyntheticOrPrivate) && sym.owner.isClass) {
361-
val errors = notPrivate(Nil, sym.info)
362-
errors.foreach { case (msg, pos) => ctx.errorOrMigrationWarning(msg, pos) }
363-
}
373+
val notPrivate = new NotPrivate
374+
val info = notPrivate(sym.info)
375+
notPrivate.errors.foreach { case (msg, pos) => ctx.errorOrMigrationWarning(msg, pos) }
376+
info
364377
}
365378
}
366379

tests/pos/i1130.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
trait A {
2+
private type Foo = Int
3+
4+
def foo: Foo = 1
5+
}
6+
class B extends A

0 commit comments

Comments
 (0)