diff options
-rw-r--r-- | src/dotty/tools/dotc/transform/PostTyper.scala | 9 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Checking.scala | 55 | ||||
-rw-r--r-- | tests/pos/i1130.scala | 6 |
3 files changed, 47 insertions, 23 deletions
diff --git a/src/dotty/tools/dotc/transform/PostTyper.scala b/src/dotty/tools/dotc/transform/PostTyper.scala index ea5c28fb1..01f9f6317 100644 --- a/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/src/dotty/tools/dotc/transform/PostTyper.scala @@ -131,8 +131,13 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran annot.derivedAnnotation(transformAnnot(annot.tree)) private def transformMemberDef(tree: MemberDef)(implicit ctx: Context): Unit = { - tree.symbol.transformAnnotations(transformAnnot) - Checking.checkNoPrivateLeaks(tree) + val sym = tree.symbol + sym.transformAnnotations(transformAnnot) + if (!sym.is(SyntheticOrPrivate) && sym.owner.isClass) { + val info1 = Checking.checkNoPrivateLeaks(sym, tree.pos) + if (info1 ne sym.info) + sym.copySymDenotation(info = info1).installAfter(thisTransformer) + } } 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 0ca121925..9b1f756b7 100644 --- a/src/dotty/tools/dotc/typer/Checking.scala +++ b/src/dotty/tools/dotc/typer/Checking.scala @@ -327,40 +327,53 @@ object Checking { * 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. + * leak testing is concerned. + * @return The `info` of `sym`, with problematic aliases expanded away. + * See i997.scala for tests, i1130.scala for a case where it matters that we + * transform leaky aliases away. */ - def checkNoPrivateLeaks(tree: MemberDef)(implicit ctx: Context): Unit = { - type Errors = List[(String, Position)] - val sym = tree.symbol - val notPrivate = new TypeAccumulator[Errors] { + def checkNoPrivateLeaks(sym: Symbol, pos: Position)(implicit ctx: Context): Type = { + class NotPrivate extends TypeMap { + type Errors = List[(String, Position)] + var errors: Errors = Nil 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 { + def apply(tp: Type): Type = tp match { case tp: NamedType => - val errors1 = + val prevErrors = errors + var tp1 = 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) { + !accessBoundary(sym).isContainedIn(tp.symbol.owner)) { + errors = (d"non-private $sym refers to private ${tp.symbol}\n in its type signature ${sym.info}", + pos) :: errors + tp + } + else mapOver(tp) + if ((errors ne prevErrors) && 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 + val savedErrors = errors + errors = prevErrors + val tp2 = apply(tp.info.bounds.hi) + if (errors eq prevErrors) tp1 = tp2 + else errors = savedErrors + } + tp1 case tp: ClassInfo => - (apply(errors, tp.prefix) /: tp.parentsWithArgs)(apply) + tp.derivedClassInfo( + prefix = apply(tp.prefix), + classParents = tp.parentsWithArgs.map(p => + apply(p).underlyingClassRef(refinementOK = false).asInstanceOf[TypeRef])) case _ => - foldOver(errors, tp) + mapOver(tp) } } - if (!sym.is(SyntheticOrPrivate) && sym.owner.isClass) { - val errors = notPrivate(Nil, sym.info) - errors.foreach { case (msg, pos) => ctx.errorOrMigrationWarning(msg, pos) } - } + val notPrivate = new NotPrivate + val info = notPrivate(sym.info) + notPrivate.errors.foreach { case (msg, pos) => ctx.errorOrMigrationWarning(msg, pos) } + info } } diff --git a/tests/pos/i1130.scala b/tests/pos/i1130.scala new file mode 100644 index 000000000..8d71de5e8 --- /dev/null +++ b/tests/pos/i1130.scala @@ -0,0 +1,6 @@ +trait A { + private type Foo = Int + + def foo: Foo = 1 +} +class B extends A |