Skip to content

Commit 0412f51

Browse files
committed
checkNoPrivateLeaks: handle references to companion members
Previously Outer2#Inner#foo failed to compile with: ``` non-private method foo refers to private value x in its type signature ``` This should compile because the boundary of `foo` is `class Outer2` and the boundary of `x` is `object Outer2`. This commit fixes this by also considering the linked boundary in `checkNoPrivateLeaks`.
1 parent a325176 commit 0412f51

File tree

3 files changed

+40
-2
lines changed

3 files changed

+40
-2
lines changed

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -353,17 +353,31 @@ object Checking {
353353
class NotPrivate extends TypeMap {
354354
type Errors = List[(String, Position)]
355355
var errors: Errors = Nil
356+
356357
def accessBoundary(sym: Symbol): Symbol =
357358
if (sym.is(Private)) sym.owner
358359
else if (sym.privateWithin.exists) sym.privateWithin
359360
else if (sym.is(Package)) sym
360361
else accessBoundary(sym.owner)
362+
363+
val symBoundary = accessBoundary(sym)
364+
365+
/** Is `other` leaked outside its access boundary ?
366+
* @pre The signature of `sym` refers to `other`
367+
*/
368+
def isLeaked(other: Symbol) =
369+
other.is(Private) && {
370+
val otherBoundary = other.owner
371+
val otherLinkedBoundary = otherBoundary.linkedClass
372+
!(symBoundary.isContainedIn(otherBoundary) ||
373+
otherLinkedBoundary.exists && symBoundary.isContainedIn(otherLinkedBoundary))
374+
}
375+
361376
def apply(tp: Type): Type = tp match {
362377
case tp: NamedType =>
363378
val prevErrors = errors
364379
var tp1 =
365-
if (tp.symbol.is(Private) &&
366-
!accessBoundary(sym).isContainedIn(tp.symbol.owner)) {
380+
if (isLeaked(tp.symbol)) {
367381
errors = (em"non-private $sym refers to private ${tp.symbol}\n in its type signature ${sym.info}",
368382
sym.pos) :: errors
369383
tp

tests/neg/leaks.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class Outer {
2+
private val x: Int = 1
3+
4+
class Inner {
5+
def foo: x.type = x // error: non-private method foo refers to private value x in its type signature
6+
}
7+
}

tests/pos/leaks.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class Outer1 {
2+
private val x: Int = 1
3+
4+
private class Inner {
5+
def foo: x.type = x // OK
6+
}
7+
}
8+
9+
object Outer2 {
10+
private val x: Int = 1
11+
}
12+
13+
class Outer2 {
14+
private class Inner {
15+
def foo: Outer2.x.type = Outer2.x // OK
16+
}
17+
}

0 commit comments

Comments
 (0)