Skip to content

Commit fe94b7a

Browse files
committed
Merge pull request #1171 from dotty-staging/fix-#1130
Have checkNotPrivate skip over private aliases.
2 parents daffba9 + 216c195 commit fe94b7a

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)