Skip to content

Commit 90c1a5f

Browse files
committed
Fix #2099: avoid loading a private member when recomputing a NamedType denot
ParamForwarding creates the following forwarder in B: private[this] def member: Int = super.member Where the type for `super.member` is `TermRef(SubA, member)` and the symbol is the `val member` in `A`. So far this is correct, but in later phases we might call `loadDenot` on this `TermRef` which will end up calling `asMemberOf`, which before this commit just did: prefix.member(name) This is incorrect in our case because `SubA` also happens to have a private `def member`, which means that our forwarder in B now forwards to a private method in a superclass, this subsequently crashes in `ExpandPrivate`. (Note: in the bytecode, a private method cannot have the same name as an overriden method, but this is already worked around in EnsurePrivate.) The fix is simple: when we recompute a member, we should only look at private members if the previous denotation was private.
1 parent c321653 commit 90c1a5f

File tree

4 files changed

+34
-2
lines changed

4 files changed

+34
-2
lines changed

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1585,8 +1585,12 @@ object Types {
15851585

15861586
protected def asMemberOf(prefix: Type)(implicit ctx: Context): Denotation =
15871587
if (name.isShadowedName) prefix.nonPrivateMember(name.revertShadowed)
1588-
else prefix.member(name)
1589-
1588+
else {
1589+
val d = lastDenotation
1590+
// Never go from a non-private denotation to a private one
1591+
if (d == null || d.symbol.is(Private)) prefix.member(name)
1592+
else prefix.nonPrivateMember(name)
1593+
}
15901594

15911595
/** (1) Reduce a type-ref `W # X` or `W { ... } # U`, where `W` is a wildcard type
15921596
* to an (unbounded) wildcard type.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Fields in A:
2+
private final int A.member$$local
3+
# Fields in SubA:
4+
5+
# Fields in B:
6+
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class A(val member: Int)
2+
3+
class SubA(member: Int) extends A(member)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
class B(member: Int) extends SubA(member)
2+
3+
object Test {
4+
def printFields(cls: Class[_]) =
5+
println(cls.getDeclaredFields.map(_.toString).sorted.deep.mkString("\n"))
6+
7+
def main(args: Array[String]): Unit = {
8+
val a = new A(10)
9+
val subA = new SubA(11)
10+
val b = new B(12)
11+
12+
println("# Fields in A:")
13+
printFields(classOf[A])
14+
println("# Fields in SubA:")
15+
printFields(classOf[SubA])
16+
println("# Fields in B:")
17+
printFields(classOf[B])
18+
}
19+
}

0 commit comments

Comments
 (0)