Skip to content

Commit f009dc0

Browse files
authored
Merge pull request #2124 from dotty-staging/fix-param-fwd
Fix parameter accessor forwarding
2 parents f45dbe7 + 40a3b94 commit f009dc0

File tree

10 files changed

+101
-13
lines changed

10 files changed

+101
-13
lines changed

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1719,7 +1719,7 @@ object Types {
17191719
* under both private and public names, so it could still be found by looking up
17201720
* the public name.
17211721
*/
1722-
final def shadowed(implicit ctx: Context): NamedType =
1722+
def shadowed(implicit ctx: Context): NamedType =
17231723
NamedType(prefix, name.shadowedName)
17241724

17251725
override def equals(that: Any) = that match {
@@ -1782,15 +1782,19 @@ object Types {
17821782
else d.atSignature(sig).checkUnique
17831783
}
17841784

1785-
override def newLikeThis(prefix: Type)(implicit ctx: Context): TermRef = {
1786-
val candidate = TermRef.withSig(prefix, name, sig)
1785+
private def fixDenot(candidate: TermRef, prefix: Type)(implicit ctx: Context): TermRef =
17871786
if (symbol.exists && !candidate.symbol.exists) { // recompute from previous symbol
17881787
val ownSym = symbol
17891788
val newd = asMemberOf(prefix, allowPrivate = ownSym.is(Private))
17901789
candidate.withDenot(newd.suchThat(_.signature == ownSym.signature))
17911790
}
17921791
else candidate
1793-
}
1792+
1793+
override def newLikeThis(prefix: Type)(implicit ctx: Context): TermRef =
1794+
fixDenot(TermRef.withSig(prefix, name, sig), prefix)
1795+
1796+
override def shadowed(implicit ctx: Context): NamedType =
1797+
fixDenot(TermRef.withSig(prefix, name.shadowedName, sig), prefix)
17941798

17951799
override def equals(that: Any) = that match {
17961800
case that: TermRefWithSignature =>

compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ package transform
44
import core._
55
import ast.Trees._
66
import Contexts._, Types._, Symbols._, Flags._, TypeUtils._, DenotTransformers._, StdNames._
7+
import Decorators._
8+
import config.Printers.typr
79

810
/** For all parameter accessors
911
*
@@ -48,7 +50,7 @@ class ParamForwarding(thisTransformer: DenotTransformer) {
4850
val candidate = sym.owner.asClass.superClass
4951
.info.decl(sym.name).suchThat(_ is (ParamAccessor, butNot = Mutable)).symbol
5052
if (candidate.isAccessibleFrom(currentClass.thisType, superAccess = true)) candidate
51-
else if (candidate is Method) inheritedAccessor(candidate)
53+
else if (candidate.exists) inheritedAccessor(candidate)
5254
else NoSymbol
5355
}
5456
def forwardParamAccessor(stat: Tree): Tree = {
@@ -65,8 +67,13 @@ class ParamForwarding(thisTransformer: DenotTransformer) {
6567
def forwarder(implicit ctx: Context) = {
6668
sym.copySymDenotation(initFlags = sym.flags | Method | Stable, info = sym.info.ensureMethodic)
6769
.installAfter(thisTransformer)
68-
val superAcc =
70+
var superAcc =
6971
Super(This(currentClass), tpnme.EMPTY, inConstrCall = false).select(alias)
72+
if (alias.owner != currentClass.superClass)
73+
// need to use shadowed in order not to accidentally address an
74+
// intervening private forwarder in the superclass
75+
superAcc = superAcc.withType(superAcc.tpe.asInstanceOf[TermRef].shadowed)
76+
typr.println(i"adding param forwarder $superAcc")
7077
DefDef(sym, superAcc.ensureConforms(sym.info.widen))
7178
}
7279
return forwarder(ctx.withPhase(thisTransformer.next))

tests/run/paramForwarding.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@ NonVal:
1313
X:
1414
private final int X.theValue$$local
1515
Y:
16-
private final int Y.theValue$$local
16+

tests/run/paramForwarding.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class Bz extends A(42) {
1919
val theValueInBz = theValue
2020
}
2121

22-
// C does not contains a field C.theValue$$local, it contains
22+
// C does not contain a field C.theValue$$local, it contains
2323
// a getter C.theValue() which only calls super.theValue()
2424
class C(override val theValue: Int) extends A(theValue)
2525

@@ -36,8 +36,8 @@ class NonVal(theValue: Int) extends A(theValue) {
3636
// X.theValue() which overrides A.theValue()
3737
class X(override val theValue: Int) extends NonVal(0)
3838

39-
// Y contains a field Y.theValue$$local accessible using the getter
40-
// Y.theValue() which overrides A.theValue()
39+
// Y does not contain a field Y.theValue$$local, it contains
40+
// a getter Y.theValue() which only calls super.theValue()
4141
class Y(override val theValue: Int) extends NonVal(theValue)
4242

4343

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1-
class A(val member: Int)
1+
class A(val member: Int) {
2+
def getAMember = member
3+
}
24

3-
class SubA(member: Int) extends A(member)
5+
class SubA(member: Int) extends A(member) {
6+
def getSubAMember = member
7+
}

tests/run/paramForwarding_separate/B_2.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
class B(member: Int) extends SubA(member)
1+
class B(member: Int) extends SubA(member) {
2+
def getMember = member
3+
}
24

35
object Test {
46
def printFields(cls: Class[_]) =
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: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
class A(val member: Int) {
2+
def getAMember = member
3+
}
4+
5+
class SubA(member: Int) extends A(member) {
6+
def getSubAMember = member
7+
}
8+
9+
class B(member: Int) extends SubA(member) {
10+
def getBMember = member
11+
}
12+
13+
object Test {
14+
def printFields(cls: Class[_]) =
15+
println(cls.getDeclaredFields.map(_.toString).sorted.deep.mkString("\n"))
16+
17+
def main(args: Array[String]): Unit = {
18+
val a = new A(10)
19+
val subA = new SubA(11)
20+
val b = new B(12)
21+
22+
println("# Fields in A:")
23+
printFields(classOf[A])
24+
println("# Fields in SubA:")
25+
printFields(classOf[SubA])
26+
println("# Fields in B:")
27+
printFields(classOf[B])
28+
}
29+
}
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: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
class B(member: Int) extends SubA(member) {
2+
def getBMember = member
3+
}
4+
5+
class SubA(member: Int) extends A(member) {
6+
def getSubAMember = member
7+
}
8+
9+
class A(val member: Int) {
10+
def getAMember = member
11+
}
12+
13+
14+
object Test {
15+
def printFields(cls: Class[_]) =
16+
println(cls.getDeclaredFields.map(_.toString).sorted.deep.mkString("\n"))
17+
18+
def main(args: Array[String]): Unit = {
19+
val a = new A(10)
20+
val subA = new SubA(11)
21+
val b = new B(12)
22+
23+
println("# Fields in A:")
24+
printFields(classOf[A])
25+
println("# Fields in SubA:")
26+
printFields(classOf[SubA])
27+
println("# Fields in B:")
28+
printFields(classOf[B])
29+
}
30+
}

0 commit comments

Comments
 (0)