Skip to content

Commit c1da44c

Browse files
committed
SI-7475 Private members are not inheritable
Exclude them from superclasses in `findMember` and in `OverridingPairs`. The odd logic in `findMember` that considered whether the selector class was owned by the owner of the candidate private symbol dates back to 2007 (bff4268), but does not appear to have any relationship to the spec. Refinement types are still able to inherit private members from all direct parents, as was needed in pos/t2399.scala. More tests are included for this scenario. In short, the logic now: - includes direct parents of refinements, - otherwise, excludes privates after the first class in the base class sequence
1 parent 8ad524f commit c1da44c

File tree

13 files changed

+117
-15
lines changed

13 files changed

+117
-15
lines changed

src/compiler/scala/tools/nsc/transform/OverridingPairs.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,12 @@ abstract class OverridingPairs {
3434
* and hidden symbols, including bridges. But it may be refined in subclasses.
3535
*
3636
*/
37-
protected def exclude(sym: Symbol): Boolean =
38-
sym.isConstructor || sym.isPrivateLocal || sym.isArtifact
37+
protected def exclude(sym: Symbol): Boolean = (
38+
sym.isConstructor
39+
|| sym.isPrivateLocal
40+
|| (sym.isPrivate && sym.owner != base)
41+
|| sym.isArtifact
42+
)
3943

4044
/** The parents of base (may also be refined).
4145
*/

src/reflect/scala/reflect/internal/Types.scala

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,22 +1069,16 @@ trait Types
10691069
//Console.println("find member " + name.decode + " in " + this + ":" + this.baseClasses)//DEBUG
10701070
var membertpe: Type = null
10711071
var required = requiredFlags
1072-
var excluded = excludedFlags | DEFERRED
1072+
var excluded: Long = excludedFlags | DEFERRED
1073+
var seenFirstNonRefinementClass: Boolean = false
10731074
var continue = true
10741075
var self: Type = null
1076+
var refinementParents: List[Symbol] = Nil
10751077

10761078
while (continue) {
10771079
continue = false
10781080
val bcs0 = baseClasses
10791081
var bcs = bcs0
1080-
// omit PRIVATE LOCALS unless selector class is contained in class owning the def.
1081-
def admitPrivateLocal(owner: Symbol): Boolean = {
1082-
val selectorClass = this match {
1083-
case tt: ThisType => tt.sym // SI-7507 the first base class is not necessarily the selector class.
1084-
case _ => bcs0.head
1085-
}
1086-
selectorClass.hasTransOwner(owner)
1087-
}
10881082
while (!bcs.isEmpty) {
10891083
val decls = bcs.head.info.decls
10901084
var entry = decls.lookupEntry(name)
@@ -1095,9 +1089,12 @@ trait Types
10951089
val excl = flags & excluded
10961090
val isMember = (
10971091
excl == 0L
1098-
&& ( (bcs eq bcs0)
1099-
|| (flags & PrivateLocal) != PrivateLocal
1100-
|| admitPrivateLocal(bcs.head)
1092+
&& (
1093+
(flags & PRIVATE) != PRIVATE // non-privates are always members
1094+
|| (
1095+
!seenFirstNonRefinementClass // classes don't inherit privates
1096+
|| refinementParents.contains(bcs.head) // refinements inherit privates of direct parents
1097+
)
11011098
)
11021099
)
11031100
if (isMember) {
@@ -1152,7 +1149,13 @@ trait Types
11521149
}
11531150
entry = decls lookupNextEntry entry
11541151
} // while (entry ne null)
1155-
// excluded = excluded | LOCAL
1152+
1153+
val sym = bcs.head
1154+
if (sym.isRefinementClass)
1155+
refinementParents :::= bcs.head.parentSymbols // keep track of direct parents of refinements
1156+
else if (sym.isClass)
1157+
seenFirstNonRefinementClass = true
1158+
11561159
bcs = if (name == nme.CONSTRUCTOR) Nil else bcs.tail
11571160
} // while (!bcs.isEmpty)
11581161
required |= DEFERRED

test/files/neg/t7475c.check

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
t7475c.scala:6: error: value a is not a member of A.this.B
2+
println(this.a) // wait, what?
3+
^
4+
t7475c.scala:7: error: value b is not a member of A.this.B
5+
println(this.b) // wait, what?
6+
^
7+
two errors found

test/files/neg/t7475c.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class A {
2+
private val a: Int = 0
3+
private[this] val b: Int = 0
4+
class B extends A {
5+
def foo(a: A) = a.a // okay
6+
println(this.a) // wait, what?
7+
println(this.b) // wait, what?
8+
}
9+
}

test/files/neg/t7475d.check

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
t7475d.scala:4: error: value priv is not a member of T.this.TT
2+
(??? : TT).priv
3+
^
4+
t7475d.scala:10: error: value priv is not a member of U.this.UU
5+
(??? : UU).priv
6+
^
7+
two errors found

test/files/neg/t7475e.check

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
t7475e.scala:8: error: value priv is not a member of Base.this.TT
2+
(??? : TT).priv
3+
^
4+
one error found

test/files/neg/t7475e.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
trait U {
2+
}
3+
4+
trait Base {
5+
private val priv = 0
6+
7+
type TT = U with T // should exclude `priv`
8+
(??? : TT).priv
9+
}
10+
11+
trait T extends Base {
12+
}

test/files/pos/t7475a.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
trait AbstractPublic {
2+
def queue: Any
3+
}
4+
trait ConcretePrivate {
5+
private val queue: Any = ()
6+
}
7+
8+
abstract class Mix
9+
extends ConcretePrivate with AbstractPublic {
10+
final def queue: Any = ()
11+
}

test/files/pos/t7475b.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
trait U {
2+
}
3+
4+
trait T {
5+
type TT = Any with T with U
6+
private val priv = 0
7+
(??? : TT).priv
8+
}

test/files/pos/t7475d.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
trait T {
2+
type TT = T with Any
3+
private val priv = 0
4+
(??? : TT).priv
5+
}
6+
7+
trait U {
8+
type UU = Any with U
9+
private val priv = 0
10+
(??? : UU).priv
11+
}

test/files/pos/t7475e.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
trait U {
2+
private val priv = 0
3+
type TT = U with T // should allow `priv`
4+
(??? : TT).priv
5+
}
6+
7+
trait Base {
8+
9+
}
10+
11+
trait T extends Base {
12+
13+
}

test/files/run/t7475b.check

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2
2+
2

test/files/run/t7475b.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
trait A { private val x = 1 }
2+
trait B { val x = 2 }
3+
trait C1 extends B with A { println(x) }
4+
trait C2 extends A with B { println(x) }
5+
6+
object Test {
7+
def main(args: Array[String]): Unit = {
8+
new C1 { }
9+
new C2 { }
10+
}
11+
}

0 commit comments

Comments
 (0)